home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 February: Tool Chest / Dev.CD Feb 94.toast / New System Software Extensions / QuickDraw™ GX v1.0ß2 / Sample Code / Printing Samples / Printer Drivers… / ImageWriterLQ / UniversalMessageIntf.c < prev    next >
Encoding:
Text File  |  1993-09-13  |  89.3 KB  |  2,953 lines  |  [TEXT/MPS ]

  1. /*---------------------------------------------------------------------------
  2. FILENAME
  3.     UniversalMessageIntf.c
  4.  
  5. DESCRIPTION
  6.     This file contains the routines which override the universal imaging 
  7.     messages that the ImageWriter LQ utilizes.
  8.         
  9.     9/13/93 - dmh - Modified for the b2 seed.
  10.     
  11. COPYRIGHT
  12.     Copyright Apple Computer, Inc. 1992
  13.     All rights reserved. 
  14.     
  15. INTERFACE ROUTINES:
  16.     SD_Initialize
  17.     SD_ShutDown
  18.     SD_JobFormatDialog
  19.     SD_JobFormatModeQuery
  20.     SD_OpenConnection
  21.     SD_StartSendPage
  22.     SD_RenderPage
  23.     SD_DefaultPrinter
  24.     SD_SetupImageData
  25.     SD_FetchTaggedData
  26.     SD_RasterPackageBitmap
  27.     SD_RasterLineFeed
  28.  
  29. -------------------------------------------------------------------------------- */
  30.  
  31. // Include the standard Mac header files 
  32. #include "MacIncludes.h"
  33.  
  34. // Include the new QuickDraw GX graphics header files 
  35. #include <graphics routines.h>
  36. #include <graphics libraries.h>
  37. #include <math routines.h>
  38. #include <qd library.h>
  39. #include <font library.h>
  40. #include <layout routines.h>
  41. #include <graphics libraries.h>
  42.  
  43. // Include the required Printing Manager header files 
  44. #include <PrintingManager.h>
  45. #include <PrintingMessages.h>
  46. #include <PrintingDrivers.h>
  47. #include <Collections.h>
  48. #include <Messages.h>
  49. #include <PrintingResTypes.h>
  50. #include <PrintingErrors.h>
  51. #include <PrintingLibraries.h>
  52.  
  53. #include <Exceptions.h>
  54.  
  55. // Include the internal driver constants and types used by this module 
  56. #include "Resources.h"
  57. #include "UniversalMessageIntf.h"
  58. #include "OldAPIMessageIntf.h"
  59. #include "DialogRoutines.h"
  60.  
  61.  
  62. /***************************************************************************************
  63. *                                                 CONSTANTS                                                         *
  64. ***************************************************************************************/                        
  65.  
  66. // ImageWriter LQ device commands
  67.  
  68. #define    kEscape                            (char) 27        // <Escape> character
  69. #define    kLineFeed                        (char) 10        // Line feed character
  70. #define    kDevStatusCommand                "\033?"            // <Escape>? - used to query the status of the printer
  71.  
  72. #define    kLowResGraphicsCommand        (char) 'G'        //    72 dpi graphics mode
  73. #define    kHighResGraphicsCommand        (char) 'C'        //    216 dpi graphics mode
  74.  
  75. #define    kLowResMarginsCommand        (char) 'F'        //    72 dpi margins command
  76. #define    kHighResMarginsCommand        (char) 'h'        //    216 dpi margins command
  77.  
  78. #define    kSetColorCommand                (char) 'K'        //    Command to select color
  79.  
  80.  
  81. // Constants used with the ScanLineRecord structure
  82.  
  83. #define    kScanLineHdrSize                15                    //    Size of the constant portion of the scan line structure
  84.  
  85.  
  86. /***************************************************************************************
  87. *                                                 TYPES                                                                 *
  88. ***************************************************************************************/                        
  89.  
  90. // ScanLineRecord -    Structure overlayed within a buffer to fill in the comands and data needed to
  91. //                            package one complete scan line.
  92. typedef struct
  93. {
  94.     char        cMarginsEscape;            // kEscape character
  95.     char        cMarginsCommand;            // Set Margins command character
  96.     char        cIndentDistance[4];        // Number of pixels to indent
  97.  
  98.     char        cColorEscape;                // kEscape character
  99.     char        cSetColorCommand;            // Set color command
  100.     char        cColor;                        // The color to use
  101.  
  102.     char        cEscape;                        // kEscape character
  103.     char        cCommand;                    // Enter graphics mode command
  104.     char        cLineLength[4];            // number of dots to print
  105.     char        iTheData[9072];            // Bits for the data, enough for one line's worth
  106. }    ScanLineRecord,
  107.     *ScanLinePtr;
  108.  
  109.  
  110. /***************************************************************************************
  111. *                                         INTERNAL ROUTINES                                                     *
  112. ***************************************************************************************/                        
  113.  
  114. /****************************************************************************************
  115.  
  116.                             Long2Dec
  117.                             
  118.     function:
  119.                 This routine converts a long integer into an ASCII string representing the
  120.                 numeric value.  If the number is less than four digits, then it's padded
  121.                 with leading zeros.
  122.                 
  123.     parameters:                
  124.                 theNumber            number to convert to a string
  125.                 emitStringHere        location in which to store the ASCII string
  126.                 
  127.     returns:
  128.                 none
  129.     
  130. ****************************************************************************************/
  131. void Long2Dec(long theNumber, Ptr emitStringHere)
  132. {    
  133.     char        aString[10];
  134.     short        i;
  135.     short        actualWidth;
  136.     short        strLength;
  137.     
  138.     NumToString(theNumber, aString);
  139.     
  140.     // Get the width of the string, check for being too small
  141.  
  142.     strLength = Length(aString);
  143.     actualWidth = strLength;
  144.     if (actualWidth < 4)
  145.         actualWidth = 4;
  146.         
  147.     // output the string, padding with leading zeros
  148.     
  149.     strLength = actualWidth - strLength;
  150.     for (i = 0; i < actualWidth; ++i)
  151.     {
  152.         *emitStringHere++ = (i < strLength) ? '0' : aString[(i + 1) - strLength];
  153.     }
  154. }
  155. /* Long2Dec */
  156.  
  157.  
  158. /****************************************************************************************
  159.  
  160.                             PrinterHasColorRibbon
  161.                             
  162.     function:
  163.                 This routine is a utility function that returns true if the desktop printer
  164.                 configuration file specifies that the printer contains a color ribbon, and
  165.                 false if it has a black and white ribbon.
  166.                 
  167.     parameters:                
  168.                 None
  169.                 
  170.     returns:
  171.                 Boolean        true => printer has color ribbon; false => black and white ribbon
  172.     
  173. ****************************************************************************************/
  174. Boolean PrinterHasColorRibbon(void)
  175. {
  176.     OSErr                    anErr;
  177.     Boolean                    hasColor = true;
  178.     Str32                    deviceName;
  179.     IWLQConfigInfoHdl        configData;
  180.     
  181.     // if not formatting to a particular device, assume color ribbon, for widest range of colorSpaces
  182.  
  183.     GXGetPrinterName(GXGetJobOutputPrinter(GXGetJob()), deviceName);
  184.     if ( Length(deviceName) > 0 )
  185.     {
  186.         // if we are going to a particular device, assume no color, as that is more common
  187.         hasColor = false;
  188.         
  189.         anErr = GXFetchDTPData(deviceName, kIWLQConfigType, kIWLQConfigID, (Handle *) &configData);
  190.         if (anErr == noErr)
  191.         {
  192.             hasColor = (*configData)->hasColorRibbon;
  193.             DisposHandle((Handle) configData);
  194.         }
  195.     }
  196.     
  197.     return(hasColor);
  198. }
  199. /* PrinterHasColorRibbon */
  200.  
  201.  
  202. /****************************************************************************************
  203.  
  204.                             PrinterHasTrays
  205.                             
  206.     function:
  207.                 This routine is a utility function that returns the number of sheet feeder trays
  208.                 that are attached to the desktop printer.  If no sheet feeder is attached, then 
  209.                 the function returns zero.
  210.                 
  211.     parameters:                
  212.                 None
  213.                 
  214.     returns:
  215.                 char        number of sheet feeder trays attached to the printer; zero if no sheet feeder
  216.     
  217. ****************************************************************************************/
  218. char PrinterHasTrays(void)
  219. {
  220.     OSErr                        anErr;
  221.     char                        numTrays = 0;    //    Assume no trays available (common case)
  222.     Str32                        deviceName;
  223.     IWLQConfigInfoHdl            configData;
  224.     
  225.     // if not formatting to a particular device, assume color ribbon, for widest range of colorSpaces
  226.  
  227.     GXGetPrinterName(GXGetJobOutputPrinter(GXGetJob()), deviceName);
  228.     if ( Length(deviceName) > 0 )
  229.     {
  230.         anErr = GXFetchDTPData(deviceName, kIWLQConfigType, kIWLQConfigID, (Handle *) &configData);
  231.         if (anErr == noErr)
  232.         {
  233.             numTrays = (*configData)->numTrays;
  234.             DisposHandle((Handle) configData);
  235.         }
  236.     }
  237.     
  238.     return(numTrays);
  239. }
  240. /* PrinterHasTrays */
  241.  
  242.  
  243. /****************************************************************************************
  244.  
  245.                             UpdateDTPConfigInfo
  246.                             
  247.     function:
  248.                 This routine is a utility function that queries the printer to determine its
  249.                 configuration (color ribbon, trays, etc.) and updates the config info. in the
  250.                 desktop printer file to reflect this new configuration.
  251.                 
  252.     parameters:                
  253.                 None
  254.                 
  255.     returns:
  256.                 OSErr        error code
  257.     
  258. ****************************************************************************************/
  259. OSErr UpdateDTPConfigInfo(void)
  260. {
  261.     OSErr                    anErr;
  262.     IWLQConfigInfoHdl        configData;
  263.     char                    statusString[9];
  264.     long                    statusLength;
  265.     Boolean                    wasSheetfeederAttached;
  266.     gxJob                    theJob = GXGetJob();
  267.         
  268.     // Determine if there was a sheetfeeder attached to the printer the last time we updated the config file
  269.     wasSheetfeederAttached = PrinterHasTrays() > 0;
  270.     
  271.     // Make a handle in which to store the config. info.
  272.     
  273.     configData = (IWLQConfigInfoHdl) NewHandleClear( sizeof(IWLQConfigInfo) );
  274.     anErr = MemError();
  275.     require(anErr == noErr, NewHandleClear);
  276.     
  277.     // Now query the printer
  278.     
  279.     statusLength = 9;
  280.     
  281.     anErr = Send_GXGetDeviceStatus(kDevStatusCommand, 2, statusString, &statusLength, "\p\n");
  282.     require(anErr == noErr, Send_GXGetDeviceStatus);
  283.     
  284.     // Scan the status string returned looking for the needed info.
  285.     
  286.     if ( (statusString[0] == 'L') && (statusString[1] == 'Q') )
  287.     {
  288.         Str32        deviceName;
  289.  
  290.         if ( statusString[3] == 'C' )    //    T => Has color ribbon
  291.         {
  292.             (*configData)->hasColorRibbon = true;
  293.         }
  294.         
  295.         if (  (statusString[3] == 'E') || 
  296.                 (statusString[3] == 'F')
  297.             )                                            //    T => Sheet feeder is installed
  298.         {
  299.             (*configData)->numTrays = statusString[4] - 0x30;
  300.         }
  301.         else
  302.         if (    (statusString[4] == 'E') ||
  303.                 (statusString[4] == 'F')
  304.             )                                            //    T => Sheet feeder is installed
  305.         {
  306.             (*configData)->numTrays = statusString[5] - 0x30;
  307.         }
  308.  
  309.         //    Update the config. file with the latest info. (our driver info.)
  310.         
  311.         GXGetPrinterName(GXGetJobOutputPrinter(theJob), deviceName);
  312.         anErr = GXWriteDTPData(deviceName, kIWLQConfigType, kIWLQConfigID, (Handle) configData);
  313.         require(anErr == noErr, GXWriteDTPData);
  314.  
  315.         // If this is the first time we've detected a sheet feeder, then we must set the tray info. (in the config. file)
  316.         // for the sheet feeder trays.  If this isn't the first time we've detected a sheetfeeder, we'll just use
  317.         // the last sheetfeeder tray settings.
  318.         
  319.         if ( (!wasSheetfeederAttached) && ((*configData)->numTrays > 0) )    //    T => No sheetfeeder before; clear the tray info.
  320.         {
  321.             GXSetTrayPaperType(1, NULL);    /* Reset the paper types from the default tray */
  322.         }
  323.         else if ( wasSheetfeederAttached && ((*configData)->numTrays == 0) )    //    T => Sheetfeeder before; clear the tray info.
  324.         {
  325.             GXSetTrayPaperType(1, NULL);    /* Reset the paper types from the first tray, ignore the others */
  326.         }
  327.     }
  328.     // else - not an LQ printer so don't change the config file info.
  329.  
  330.     // Dump the confog. data handle
  331.     DisposHandle((Handle) configData);
  332.  
  333.     return(anErr);
  334.     
  335.     
  336. /******* Clean-up *******/
  337.  
  338. GXWriteDTPData:
  339. Send_GXGetDeviceStatus:
  340.     DisposHandle((Handle) configData);
  341.     
  342. NewHandleClear:
  343.     return(anErr);
  344. }
  345. /* UpdateDTPConfigInfo */
  346.  
  347.  
  348. /****************************************************************************************
  349.  
  350.                             FixRoundRectangle
  351.                             
  352.     function:
  353.                 This routine is a utility function which rounds the coordinate values within 
  354.                 the gxRectangle passed in.
  355.                 
  356.     parameters:                
  357.                 r            gxRectangle whose coordinates are to be rounded
  358.                 
  359.     returns:
  360.                 None
  361.     
  362. ****************************************************************************************/
  363. void FixRoundRectangle(gxRectangle *r)
  364. {
  365.     r->top         = ff(FixRound(r->top));
  366.     r->left         = ff(FixRound(r->left));
  367.     r->bottom     = ff(FixRound(r->bottom));
  368.     r->right     = ff(FixRound(r->right));
  369. }
  370. /* FixRoundRectangle */
  371.  
  372.  
  373. /****************************************************************************************
  374.  
  375.                             UpdatePaperFeed
  376.                             
  377.     function:
  378.                 This routine is a utility routine for updating the auto-feed setting of the
  379.                 job.
  380.                 
  381.                 NOTE: THIS UTILITY ROUTINE NEEDS TO BE MOVED TO THE PUBLIC INTERFACE SO WE
  382.                 DON'T NEED TO INCLUDE IT HERE IN THIS DRIVER.  IT CAME FROM DIALOGUTILITIES.C.
  383.                 
  384.     parameters:
  385.                 theJob        the Job whose auto-feed boolean is to be set
  386.                 autoFeedOn    true => switch job to auto-feed; false => switch to manual feed
  387.                 
  388.     returns:
  389.                 OSErr
  390.  
  391. ****************************************************************************************/
  392. OSErr UpdatePaperFeed(gxJob theJob, Boolean autoFeedOn)
  393. {
  394.     OSErr            anErr;
  395.     Collection    jobCollection = GXGetJobCollection(theJob);
  396.  
  397.     anErr = AddCollectionItem ( jobCollection,
  398.                                  gxPaperFeedTag,
  399.                                  gxPrintingTagID,
  400.                                  1,
  401.                                  &autoFeedOn);
  402.  
  403.     check(anErr == noErr);
  404.     return(anErr);
  405. }
  406. /* UpdatePaperFeed */
  407.  
  408.  
  409. /****************************************************************************************
  410.  
  411.                             RetrieveJobItem
  412.                             
  413.     function:
  414.                 NOTE: THIS UTILITY ROUTINE NEEDS TO BE MOVED TO THE PUBLIC INTERFACE SO WE
  415.                 DON'T NEED TO INCLUDE IT HERE IN THIS DRIVER.  IT CAME FROM DIALOGUTILITIES.C.
  416.  
  417.     parameters:                
  418.  
  419.     returns:
  420.  
  421. ****************************************************************************************/
  422. OSErr    RetrieveJobItem( gxJob theJob, CollectionTag tag, long id, void *theValue, long *itemSize )
  423. {
  424.     OSErr    anErr = noErr;
  425.     Collection    theCollection = GXGetJobCollection( theJob );
  426.  
  427.     anErr = GetCollectionItem (theCollection,
  428.                                 tag,
  429.                                 id,
  430.                                 itemSize,
  431.                                 theValue );
  432.  
  433.     return( anErr );
  434.  
  435. }
  436. /* RetrieveJobItem */
  437.  
  438.  
  439. /****************************************************************************************
  440.  
  441.                             RetrievePaperFeed
  442.                             
  443.     function:
  444.                 NOTE: THIS UTILITY ROUTINE NEEDS TO BE MOVED TO THE PUBLIC INTERFACE SO WE
  445.                 DON'T NEED TO INCLUDE IT HERE IN THIS DRIVER.  IT CAME FROM DIALOGUTILITIES.C.
  446.     
  447.     parameters:
  448.     
  449.     returns:
  450.  
  451. ****************************************************************************************/
  452. OSErr    RetrievePaperFeed(gxJob theJob, Boolean *autoFeedOn, Boolean *feedLocked)
  453. {
  454.     #pragma unused (feedLocked)
  455.     
  456.     long    paperFeedSize = 1;
  457.  
  458.     return( RetrieveJobItem(     theJob, 
  459.                                 gxPaperFeedTag, 
  460.                                 gxPrintingTagID, 
  461.                                 autoFeedOn, 
  462.                                 &paperFeedSize ) );
  463.  
  464. }
  465. /* RetrievePaperFeed */
  466.  
  467.  
  468. /****************************************************************************************
  469.  
  470.                             RetrieveManualFeedPaper
  471.                             
  472.     function:
  473.                 NOTE: THIS UTILITY ROUTINE NEEDS TO BE MOVED TO THE PUBLIC INTERFACE SO WE
  474.                 DON'T NEED TO INCLUDE IT HERE IN THIS DRIVER.  IT CAME FROM DIALOGUTILITIES.C.
  475.  
  476.     parameters:                
  477.  
  478.     returns:
  479.  
  480. ****************************************************************************************/
  481. OSErr RetrieveManualFeedPaper(gxJob theJob, gxManualFeedInfo **paperTypeNameList)
  482. {
  483.     OSErr        anErr;
  484.     Collection    jobCollection = GXGetJobCollection(theJob);
  485.     Size        ptrSize;
  486.     
  487.     anErr = GetCollectionItemInfo(jobCollection, gxManualFeedTag, gxPrintingTagID,
  488.                                   0, &ptrSize, 0);
  489.     
  490.     
  491.     if (anErr == noErr) {
  492.     
  493.         *paperTypeNameList = (gxManualFeedInfo *) NewPtrClear(ptrSize);
  494.         anErr = MemError();
  495.         nrequire( anErr, NewPtrClearFails );
  496.  
  497.         anErr = GetCollectionItem( jobCollection, 
  498.                                     gxManualFeedTag, 
  499.                                     gxPrintingTagID, 
  500.                                     NULL,
  501.                                     *paperTypeNameList); 
  502.         }
  503.  
  504. NewPtrClearFails:
  505.     return( anErr );
  506. }
  507. /* RetrieveManualFeedPaper */
  508.  
  509.  
  510. /****************************************************************************************
  511.  
  512.                             IsManualFeedPaperType
  513.                             
  514.     function:
  515.                 NOTE: THIS UTILITY ROUTINE NEEDS TO BE MOVED TO THE PUBLIC INTERFACE SO WE
  516.                 DON'T NEED TO INCLUDE IT HERE IN THIS DRIVER.  IT CAME FROM DIALOGUTILITIES.C.
  517.     
  518.     parameters:
  519.     
  520.     returns:
  521.  
  522. ****************************************************************************************/
  523. OSErr    IsManualFeedPaperType(gxPaperType thePaperType, Boolean *IsManualFeed)
  524. {
  525.     OSErr                anErr;
  526.     gxJob                theJob = GXGetJob();
  527.     Boolean                fAutoFeedOn;
  528.     gxManualFeedInfo    *paperTypeNameList = nil;
  529.     short                nameCount, idx;
  530.     Str31                paperName;
  531.  
  532.     *IsManualFeed    = false;
  533.     anErr = RetrievePaperFeed( theJob, &fAutoFeedOn, nil );
  534.     nrequire( anErr, RetrievePaperFeedFails );
  535.     
  536.     if ( !fAutoFeedOn ) {
  537.  
  538.         anErr = RetrieveManualFeedPaper( theJob, &paperTypeNameList );
  539.         
  540.         if (anErr == collectionItemNotFoundErr) {
  541.         
  542.             *IsManualFeed = true;
  543.             anErr = noErr;
  544.             
  545.         } else {
  546.         
  547.             nrequire( anErr, RetrieveManualFeedPaperFails );
  548.             
  549.             GXGetPaperTypeName( thePaperType, paperName );
  550.             nameCount = paperTypeNameList->numPaperTypeNames;
  551.             
  552.             for (idx = 0; idx < nameCount; ++idx) {
  553.  
  554.                 Ptr pName = &paperTypeNameList->paperTypeNames[idx];
  555.                 
  556.                 if ( IUMagIDString(    paperName, 
  557.                                     pName,
  558.                                     paperName[0] + 1,
  559.                                     *pName + 1)     == 0  ) {
  560.                     *IsManualFeed = true;
  561.                     break;
  562.                     }
  563.                 }
  564.             }
  565.         }
  566.  
  567.     
  568. RetrieveManualFeedPaperFails:
  569.  
  570.     if ( paperTypeNameList != nil )
  571.         DisposPtr( (Ptr) paperTypeNameList );
  572.         
  573. RetrievePaperFeedFails:
  574.  
  575.     return( anErr );
  576. }
  577. /* IsManualFeedPaperType */
  578.  
  579.  
  580. /****************************************************************************************
  581.  
  582.                             JobIsBestQuality
  583.                             
  584.     function:
  585.                 This routine is called to determine if the job the driver is currently
  586.                 processing is to be output in best quality or rough quality. The function
  587.                 returns true if best quality, and false otherwise.
  588.                 
  589.     parameters:    
  590.                 None
  591.                 
  592.     returns:
  593.                 Boolean        true if best quality job; false otherwise
  594.     
  595. ****************************************************************************************/
  596. Boolean JobIsBestQuality(void)
  597. {
  598.     OSErr                anErr;
  599.     Boolean                isFinal;
  600.     gxQualityInfo        jobQualitySettings;
  601.     long                itemSize = sizeof(jobQualitySettings);
  602.  
  603.     // Retrieve the quality setting info from the job
  604.     anErr = GetCollectionItem(GXGetJobCollection(GXGetJob()), gxQualityTag, gxPrintingTagID, &itemSize, &jobQualitySettings);
  605.     check(anErr == noErr);
  606.     
  607.     isFinal = (anErr == noErr) && (jobQualitySettings.currentQuality == 1);
  608.  
  609.     return(isFinal);
  610. }
  611. /* JobIsBestQuality */
  612.  
  613.  
  614. /****************************************************************************************
  615.  
  616.                             MakeNewPrinterViewDevice
  617.                             
  618.     function:
  619.                 This routine is called to add a new view device to the printer object.  The
  620.                 gxViewDevice that's added will have a resolution of 216 dpi, and will have the
  621.                 set of colors specified by the theColors parameter.  The newly created 
  622.                 view device is added to the printer object.
  623.                 
  624.     parameters:                
  625.                 thePrinter        the newly allocated printer object
  626.                 theColors        the colors over which the view device is defined
  627.                 numColrs            the number of colors in the set
  628.                 
  629.     returns:
  630.                 OSErr
  631.                 
  632. ****************************************************************************************/
  633. OSErr MakeNewPrinterViewDevice(    gxPrinter    thePrinter,
  634.                                 gxSetColor        theColors[],
  635.                                 short            numColors)
  636. {
  637.     OSErr             anErr = noErr;
  638.     gxViewDevice     vd;
  639.     gxMapping        vdMapping;
  640.     gxShape            theBitmap;
  641.     gxColorSet        theColorSet;
  642.     
  643.     // Create the new gxViewDevice using a fake gxBitmap 
  644.     {
  645.         gxBitmap    aBitmap;
  646.         
  647.         aBitmap.pixelSize    = 1;
  648.         aBitmap.rowBytes    = 0;
  649.         aBitmap.width        = 0;
  650.         aBitmap.height        = 0;
  651.         aBitmap.image        = nil;
  652.         aBitmap.space        = gxNoSpace;
  653.         aBitmap.set            = nil;
  654.         aBitmap.profile    = nil;
  655.         
  656.         theBitmap = GXNewBitmap(&aBitmap, nil);
  657.         require_action( GXGetGraphicsError(nil) == noErr, GXNewBitmap, anErr = GXGetGraphicsError(nil); );
  658.         
  659.         vd = GXNewViewDevice(gxScreenViewDevices, theBitmap);
  660.         require_action( GXGetGraphicsError(nil) == noErr, GXNewViewDevice, anErr = GXGetGraphicsError(nil); );
  661.  
  662.         // Dispose of the reference to the temporary gxShape
  663.         GXDisposeShape(theBitmap);
  664.     }
  665.     
  666.     // Now set the view device's color space based on the set of colors passed in 
  667.     {
  668.         theColorSet = GXNewColorSet(gxRGBSpace, numColors, theColors);
  669.         require_action( GXGetGraphicsError(nil) == noErr, GXNewColorSet, anErr = GXGetGraphicsError(nil); );
  670.  
  671.         SetViewDeviceColorSet(vd, theColorSet);
  672.         require_action( GXGetGraphicsError(nil) == noErr, SetViewDeviceColorSet, anErr = GXGetGraphicsError(nil); );
  673.     
  674.         // Dispose of the reference to the temporary gxShape
  675.         GXDisposeColorSet(theColorSet);
  676.     }
  677.     
  678.     // Change the gxViewDevice gxMapping to include the scaling factor from 72dpi (screen) to 216 dpi (device). 
  679.     {
  680.         ResetMapping(&vdMapping);
  681.         ScaleMapping(&vdMapping, ff(3), ff(3), ff(0), ff(0));
  682.         
  683.         GXSetViewDeviceMapping(vd, &vdMapping);
  684.     }
  685.     
  686.     // Add the newly created gxViewDevice to the printer object 
  687.  
  688.     anErr = GXAddPrinterViewDevice(thePrinter, vd);
  689.     require_action( GXGetGraphicsError(nil) == noErr, GXAddPrinterViewDevice, anErr = GXGetGraphicsError(nil); );
  690.     
  691.     return(anErr);
  692.     
  693.     
  694. /******* Clean-up *******/
  695.  
  696. SetViewDeviceColorSet:
  697.     GXDisposeColorSet(theColorSet);
  698.  
  699. GXAddPrinterViewDevice:
  700. GXNewColorSet:
  701.     GXDisposeViewDevice(vd);
  702.     return(anErr);
  703.  
  704. GXNewViewDevice:
  705.     GXDisposeShape(theBitmap);
  706.  
  707. GXNewBitmap:
  708.     return(anErr);
  709. }
  710. /* MakeNewPrinterViewDevice */
  711.  
  712.  
  713. /****************************************************************************************
  714.  
  715.                             WriteDraftChars
  716.                             
  717.     function:
  718.                 This routine is called to output a single character in the native set of the
  719.                 printer.  The draftTable parameter contains long word entries for each possible
  720.                 character that can be printed.  Each long word entry is composed of two word entries,
  721.                 where the first word represents the primary character to output and the second
  722.                 word optionally specifies an overstrike character.  If an overstrike character
  723.                 is specified, then we will overstrike the second character on the first.  The format
  724.                 of each word is the same and is as follows:
  725.                 
  726.                 bit 15         -    0 => don't backspace before writing character
  727.                                     1 => backspace first before printing the character
  728.                 
  729.                 bits 14:12    -    0
  730.  
  731.                 bits 11:8    -    national character set to invoke (e.g. kAmerican)
  732.  
  733.                 bits 7:0        -    the character to send to the printer (must be != 0 to be output)
  734.                 
  735.     parameters:    
  736.                 draftTable        Handle to an array of long word entries that describe how to output
  737.                                     each printable character in draft mode
  738.                 draftChar        Pointer to the ASCII characters that are to be output
  739.                 numChars            Number of characters to be output
  740.                 
  741.     returns:
  742.                 OSErr
  743.     
  744. ****************************************************************************************/
  745. OSErr WriteDraftChars(long **draftTable, unsigned char *draftChar, long numChars)
  746. {
  747.     OSErr        anErr = noErr;
  748.     char        outputChars[20];                // a maximum of 20 characters can be generated
  749.     short        charCount;                    
  750.     
  751.     // For each character in the buffer, determine how to map the character to a draft character
  752.     for (; numChars > 0; --numChars, ++draftChar)
  753.     {
  754.         // No characters yet for this output character
  755.         charCount = 0;
  756.             
  757.         // Only consider characters in the printable range
  758.         if (*draftChar >= 0x20)
  759.         {
  760.             unsigned long    draftControl = (*draftTable)[*draftChar-0x20];    // Fetch native mode long word corresponding to this character
  761.             unsigned char    outChar;
  762.             unsigned char    nationalSet;
  763.             short                i;
  764.             
  765.             // For each word which composes the native mode long word 
  766.             for (i = 1; i >= 0; --i)
  767.             {
  768.                 // Should we send a backspace character (to overstrike)?
  769.                 if ( (draftControl & 0x80000000) != 0 )
  770.                     outputChars[charCount++] = 0x08;
  771.                 
  772.                 outChar = (draftControl >> 16) & 0xFF;
  773.                 if (outChar != 0)
  774.                 {
  775.                     // Determine the national character set to select
  776.                     nationalSet = (draftControl >> 24) & 0xF;    
  777.     
  778.                     //    Is this character in the standard, built-in character set?
  779.                     if (nationalSet == kAmerican)
  780.                     {
  781.                         outputChars[charCount++] = outChar;
  782.                     }
  783.                     else    //    T => Must select a foreign language character set 
  784.                     {
  785.                         outputChars[charCount++] = 0x1B;
  786.                         outputChars[charCount++] = 0x44;
  787.                         outputChars[charCount++] = nationalSet;
  788.                         outputChars[charCount++] = 0x00;
  789.                         outputChars[charCount++] = outChar;
  790.                         outputChars[charCount++] = 0x1B;                // We always switch back to the kAmerican character set
  791.                         outputChars[charCount++] = 0x5A;
  792.                         outputChars[charCount++] = 0x07;
  793.                         outputChars[charCount++] = 0x00;
  794.                     }
  795.                 }
  796.                 
  797.                 // Take the next (low) word and process it (if we're not all done)
  798.                 draftControl <<= 16;
  799.             }    
  800.         }
  801.             
  802.         // If we generated any data, send it out now
  803.         if (charCount > 0)
  804.             anErr = Send_GXBufferData(outputChars, charCount, gxNoBufferOptions);
  805.     }
  806.         
  807.     return(anErr);    
  808.     
  809. /* WriteDraftChars */
  810.  
  811.  
  812. /****************************************************************************************
  813.  
  814.                             GetPointerThisBig
  815.                             
  816.     function:
  817.                 This routine is called to return a pointer (in the heap) to the number of
  818.                 bytes specified by numBytes.  If the pointer is already large enough, then
  819.                 this routine simply returns the existing pointer.  Otherwise, it allocates
  820.                 a new pointer (possibly disposing of the old one) of the specified size.
  821.                 
  822.     parameters:    
  823.                 theBuff            returns a pointer to the allocated buffer 
  824.                 numBytes            required size of the pointer returned (in bytes)
  825.                 
  826.     returns:
  827.                 OSErr
  828.     
  829. ****************************************************************************************/
  830. OSErr GetPointerThisBig(Ptr *theBuff, long numBytes) 
  831. {
  832.     OSErr        anErr = noErr;
  833.     
  834.     if (*theBuff != nil)
  835.     {
  836.         if ( GetPtrSize(*theBuff) < numBytes )    //    T => Won't be big enough; make a new one
  837.         {
  838.             DisposPtr(*theBuff);
  839.             *theBuff = nil;
  840.         }
  841.     }
  842.  
  843.     if (*theBuff == nil)
  844.     {
  845.         *theBuff = NewPtrClear(numBytes);
  846.         anErr = MemError();
  847.     }
  848.     
  849.     return(anErr);
  850. }
  851. /* GetPointerThisBig */
  852.  
  853.  
  854. /****************************************************************************************
  855.  
  856.                             GetTextAndPosition
  857.                             
  858.     function:
  859.                 This routine is called to return information about the layout gxShape
  860.                 referenced by the theShape parameter.  It returns a pointer to the
  861.                 text data in theChars, the number of characters in the data in numChars, and
  862.                 a pointer to the positions of the characters in textPositions.  The caller
  863.                 is responsible for disposing of the pointers returned in theChars and
  864.                 textPositions.
  865.                 
  866.     parameters:    
  867.                 theShape            reference to the gxShape to be examined
  868.                 theChars            returns a pointer to the text characters
  869.                 numChars            returns the number of characters in the text gxShape
  870.                 textPosition    returns the position of the layout gxShape
  871.                 
  872.     returns:
  873.                 OSErr
  874.     
  875. ****************************************************************************************/
  876. OSErr GetTextAndPosition(    gxShape            theShape, 
  877.                             Ptr            *theChars, 
  878.                             long            *numChars, 
  879.                             gxPoint            *textPosition)
  880. {
  881.     OSErr        anErr = noErr;
  882.     long        textLength;
  883.     
  884.     // Determine the size of the text data and the position of the text
  885.     textLength = GXGetLayout(theShape, nil, nil, nil, nil, nil, nil, nil, nil, textPosition);
  886.  
  887.     // Make sure we have a buffer pointer large enough to hold all of the data
  888.     
  889.     anErr = GetPointerThisBig(theChars, textLength);
  890.     require(anErr == noErr, CantAllocTextBuff);
  891.     
  892.     // Now we retrieve the text
  893.     GXGetLayout(theShape, *theChars, nil, nil, nil, nil, nil, nil, nil, nil);
  894.     
  895.     // Remember the number of characters in the gxShape
  896.     *numChars = textLength;
  897.     
  898.  
  899. /******* Clean-up *******/
  900.  
  901. CantAllocTextBuff:
  902.     return(anErr);
  903. }
  904. /* GetTextAndPosition */
  905.  
  906.  
  907. /****************************************************************************************
  908.  
  909.                             PrintPageInDraftMode
  910.                             
  911.     function:
  912.                 This routine is called to print a page using the native character set in the
  913.                 printer.  The page to print is referenced by the thePage parameter.  The routine
  914.                 walks through the picture looking for layout gxShapes.  Each of these
  915.                 gxShapes is imaged using the native character set; all other gxShapes are ignored.
  916.                 This routine assumes the gxShapes within the picture are y-sorted.
  917.                 
  918.     parameters:    
  919.                 thePage        Reference to the page gxShape that's to be printed
  920.                 imageData    pointer to the raster image data
  921.                 
  922.     returns:
  923.                 OSErr
  924.     
  925. ****************************************************************************************/
  926. OSErr PrintPageInDraftMode(gxShape thePage, gxRasterImageDataHdl imageData)
  927. {
  928.     OSErr                    anErr = noErr;
  929.     long                    i;
  930.     long                    numItems;
  931.     Fixed                    currYPos = ff(0);
  932.     Ptr                        theChars = nil;
  933.     long                    numChars = 0;
  934.     gxPoint                    textPosition;
  935.     Fixed                    oldTextSize = ff(0);
  936.     SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  937.     
  938.     // Since the page picture we need to process is a picture gxShape that's embedded in
  939.     // thePage (a gxShape containing one item => a picture), we need to extract the real
  940.     // page picture from thePage.
  941.     
  942.     thePage = GetPictureItem(thePage, 1, nil, nil, nil, nil);
  943.     numItems = GXGetPicture(thePage, nil, nil, nil, nil);
  944.     
  945.     // For each gxShape within the picture, check its type and process it accordingly
  946.     
  947.     for (i = 1; i <= numItems; ++i)
  948.     {
  949.         gxShape                theShape;
  950.         short                theType;
  951.         
  952.         theShape = GetPictureItem(thePage, i, nil, nil, nil, nil);
  953.         theType = GXGetShapeType(theShape);
  954.         
  955.         if (theType == gxLayoutType)    //    T => We have a layout gxShape
  956.         {
  957.             fixed        textSize;
  958.             char        buff[12];
  959.             char        theFace;
  960.             short        cmndBuffSz;
  961.             
  962.             // First determine the gxStyle in which we're printing
  963.             
  964.             theFace = GetStyleCommonFace( GXGetShapeStyle(theShape) );
  965.             
  966.             buff[0] = kEscape;
  967.             if ( (theFace & bold) != 0 )    //    T => Turn bold facing on
  968.                 buff[1] = '!';
  969.             else                                    //    T => Turn it off
  970.                 buff[1] = '"';
  971.             
  972.             buff[2] = kEscape;
  973.             if ( (theFace & underline) != 0 )    //    T => Turn underline facing on
  974.                 buff[3] = 'X';
  975.             else                                            //    T => Turn it off
  976.                 buff[3] = 'Y';
  977.                 
  978.             cmndBuffSz = 4;
  979.             
  980.             // Next determine if we need to change the size of the gxFont being used
  981.             
  982.             textSize = GXGetShapeTextSize(theShape);
  983.             if (textSize != oldTextSize)    //    T => Must issue LQ command to change gxFont size
  984.             {
  985.                 buff[4] = kEscape;                //    The first escape command selects black color
  986.                 buff[5] = kSetColorCommand;
  987.                 buff[6] = '0';
  988.                 
  989.                 buff[7] = kEscape;                //    The second escape command selects a draft gxFont
  990.                 buff[8] = 'a';
  991.                 buff[9] = '1';
  992.                 
  993.                 buff[10] = kEscape;                //    The third escape command selects the character pitch
  994.                 
  995.                 if ( textSize <= ff(10) )    //    T => Select 10 cpi
  996.                 {
  997.                     buff[11] = 'N';
  998.                 }
  999.                 else    //    T => All other sizes get mapped to 12 cpi
  1000.                 {
  1001.                     buff[11] = 'E';
  1002.                 }
  1003.                 
  1004.                 // Remember the last text size
  1005.                 oldTextSize = textSize;    
  1006.                 
  1007.                 // Adjust the size of the data to be sent to the printer
  1008.                 cmndBuffSz += 8;
  1009.             }
  1010.             // else - no change in gxFont size
  1011.             
  1012.             // Send the commands to the printer
  1013.             anErr = Send_GXBufferData(buff, cmndBuffSz, gxDontSplitBuffer);
  1014.             require(anErr == noErr, CantSendFontCmnd);
  1015.  
  1016.             // Get the ASCII text and the starting position of the data
  1017.             anErr = GetTextAndPosition(theShape, &theChars, &numChars, &textPosition);
  1018.             require(anErr == noErr, CantGetTextAndPos);
  1019.             
  1020.             if ( (currYPos != ff(0)) && (currYPos != textPosition.y) )    //    T => Moving to a lower line, finish the last ;line with a CR
  1021.             {
  1022.                 char        c = 0x0D;
  1023.                 
  1024.                 anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
  1025.                 require(anErr == noErr, CantSendCRCmnd);
  1026.             }
  1027.             
  1028.             // Position the print head to the proper location on the page
  1029.             {
  1030.                 gxMapping            theMapping;
  1031.                 short                lineFeedSize;
  1032.                 Str255                positionCmndsBuff;
  1033.                 unsigned long        bytesInBuff = 0;
  1034.                 char                *p;
  1035.  
  1036.                 GXGetShapeMapping(theShape, &theMapping);
  1037.                 MapPoints(&theMapping, (long) 1, &textPosition);    //    Just map the first gxPoint
  1038.                 
  1039.                 // Now position the print head vertically
  1040.  
  1041.                 lineFeedSize = (textPosition.y - currYPos) >> 16;
  1042.                 anErr = Send_GXRasterLineFeed(&lineFeedSize, positionCmndsBuff, &bytesInBuff, imageData);
  1043.                 require(anErr == noErr, CantEmitLineFeeds);
  1044.                 
  1045.                 // Update the current Y position pointer on the page
  1046.                 currYPos = textPosition.y;
  1047.  
  1048.                 // Now position the print head horizontally on the page
  1049.  
  1050.                 p = &positionCmndsBuff[bytesInBuff];        
  1051.                 *p++ = kEscape;
  1052.                 *p++ = kLowResMarginsCommand;
  1053.                 Long2Dec((*hGlobals)->leftMargin + FixedToInt(textPosition.x), p);    // Convert left margin into ASCII and place it at the start of the scan line
  1054.                 
  1055.                 // Update the number of bytes in the buffer
  1056.                 bytesInBuff += 6;
  1057.  
  1058.                 // Send the positioning info to the printer
  1059.                 anErr = Send_GXBufferData(positionCmndsBuff, bytesInBuff, gxDontSplitBuffer);
  1060.                 require(anErr == noErr, CantSendPositionCmnds);
  1061.             }
  1062.             
  1063.             // Now we send the text data to the printer
  1064.             anErr = WriteDraftChars((long **) (*hGlobals)->draftTable, theChars, numChars);
  1065.             require(anErr == noErr, CantWriteChars);
  1066.         }
  1067.     }    // for
  1068.  
  1069.     // Send one last CR to wrap the last line (if there was one)
  1070.     {
  1071.         char        c = 0x0D;
  1072.         
  1073.         anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
  1074.     }
  1075.  
  1076.  
  1077. /******* Clean-up *******/
  1078.  
  1079. CantWriteChars:
  1080. CantSendPositionCmnds:
  1081. CantEmitLineFeeds:
  1082. CantSendCRCmnd:
  1083. CantGetTextAndPos:
  1084. CantSendFontCmnd:
  1085.     if (theChars != nil)
  1086.         DisposPtr(theChars);
  1087.                 
  1088.     return(anErr);
  1089. }
  1090. /* PrintPageInDraftMode */
  1091.  
  1092.  
  1093. /***************************************************************************************
  1094. *                                         INTERFACE ROUTINES                                                     *
  1095. ***************************************************************************************/                        
  1096.  
  1097. /****************************************************************************************
  1098.  
  1099.                             SD_Initialize
  1100.                             
  1101.     function:
  1102.                 This routine is called when a new job is created to perform some job-oriented
  1103.                 task, such as conducting dialogs, spooling, and imaging.  It allocates the
  1104.                 driver's globals handle and initializes it.
  1105.                 
  1106.     parameters:    
  1107.                 None
  1108.                 
  1109.     returns:
  1110.                 OSErr
  1111.     
  1112. ****************************************************************************************/
  1113. OSErr SD_Initialize(void)
  1114. {
  1115.     OSErr                 anErr;
  1116.     SpecGlobalsHdl     hGlobals;
  1117.     
  1118.     // Allocate the driver's global handle 
  1119.  
  1120.     hGlobals = (SpecGlobalsHdl) NewHandleClear(kSpecGlobalsRecLen);
  1121.     anErr = MemError();
  1122.     require(anErr == noErr, NewHandleClear);
  1123.     
  1124.     // Tell the Printing Manager to save our globals handle for us 
  1125.     SetMessageHandlerInstanceContext(hGlobals);
  1126.  
  1127.     return(anErr);
  1128.     
  1129.     
  1130. /******* Clean-up *******/
  1131.  
  1132. NewHandleClear:
  1133.     return(anErr);
  1134. }
  1135. /* SD_Initialize */
  1136.  
  1137.  
  1138. /****************************************************************************************
  1139.  
  1140.                             SD_ShutDown
  1141.                             
  1142.     function:
  1143.                 This routine is called when a job-oriented task has completed and the 
  1144.                 message chain is being destroyed.  This routine disposes of the driver's
  1145.                 globals handle..
  1146.                 
  1147.     parameters:        
  1148.                 None
  1149.                 
  1150.     returns:
  1151.                 OSErr
  1152.     
  1153. ****************************************************************************************/
  1154. OSErr SD_ShutDown(void)
  1155. {
  1156.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  1157.     
  1158.     // Dump the draft table if we loaded it
  1159.     if ( (*hGlobals)->draftTable != nil )
  1160.         DisposHandle((*hGlobals)->draftTable);
  1161.     
  1162.     // Dump the driver's globals handle if it was allocated 
  1163.     if (hGlobals != nil)
  1164.         DisposHandle((Handle) hGlobals);
  1165.  
  1166.     // Make sure the Printing Manager no longer has a reference to our globals handle 
  1167.     SetMessageHandlerInstanceContext(nil);
  1168.         
  1169.     return(noErr);
  1170. }
  1171. /* SD_ShutDown */
  1172.  
  1173.  
  1174. /****************************************************************************************
  1175.  
  1176.                             SD_JobFormatDialog
  1177.                             
  1178.     function:
  1179.                 This routine is called when the Printing Manager is called to display the
  1180.                 Job gxFormat dialog.  This message gives the driver the opportunity to determine
  1181.                 the job format modes that are supported by the application.  If the application
  1182.                 supports text, then we set the preferred job format mode to be 'text'.  The preferred
  1183.                 format mode is the format mode that becomes active when the user selects Direct
  1184.                 Mode from the Job gxFormat dialog box.
  1185.                 
  1186.     parameters:                
  1187.                 dlgResult        result of dismissing the dialog (ok or cancel)
  1188.                 
  1189.     returns:
  1190.                 OSErr
  1191.                 
  1192. ****************************************************************************************/
  1193. OSErr SD_JobFormatDialog(gxDialogResult *dlgResult)
  1194. {
  1195.     OSErr                     anErr;
  1196.     gxJobFormatModeTableHdl    theJobFormatModeList;
  1197.     gxJob                     theJob = GXGetJob();
  1198.     
  1199.     // Did the application specify any job format modes?
  1200.     
  1201.     anErr = GXGetAvailableJobFormatModes(&theJobFormatModeList);
  1202.     if ( (anErr == noErr) && (theJobFormatModeList != nil) )
  1203.     {
  1204.         long    i;
  1205.  
  1206.         // Examine each job format mode to determine if 'text' mode is supported.  If
  1207.         // it is, then we make it the preferred format mode for Direct Mode printing
  1208.         
  1209.         for (i = 0; i <= (*theJobFormatModeList)->numModes - 1; ++i) 
  1210.         {
  1211.             if ((*theJobFormatModeList)->modes[i] == gxTextJobFormatMode) 
  1212.             {
  1213.                 // Tell Printing Manger we support 'text' Direct Mode, but that we also
  1214.                 // support other modes.
  1215.                 
  1216.                 GXSetPreferredJobFormatMode(gxTextJobFormatMode, false);
  1217.                 break;
  1218.             }
  1219.         }
  1220.         
  1221.         // Dump the temporary handle we were issued
  1222.         DisposHandle((Handle)theJobFormatModeList);
  1223.     }
  1224.         
  1225.     // New we let the dialog be displayed. 
  1226.  
  1227.     anErr = Forward_GXJobDefaultFormatDialog(dlgResult);
  1228.     require(anErr == noErr, Forward_GXJobFormatDialog);
  1229.     
  1230.     return(anErr);
  1231.     
  1232.     
  1233. /******* Clean-up *******/
  1234.  
  1235. Forward_GXJobFormatDialog:
  1236.     return(anErr);
  1237. }
  1238. /* SD_JobFormatDialog */
  1239.  
  1240.  
  1241. /****************************************************************************************
  1242.  
  1243.                             SD_JobPrintDialog
  1244.                             
  1245.     function:
  1246.                 This routine is called when the Printing Manager is called to display the
  1247.                 Job dialog.  This message gives the driver the opportunity to add the LQ Options
  1248.                 panel to the dialog.  This panel provides the user the option to choose between
  1249.                 bidirectional and unidirectional printing.
  1250.                 
  1251.     parameters:                
  1252.                 dlgResult        result of dismissing the dialog (ok or cancel)
  1253.                 
  1254.     returns:
  1255.                 OSErr
  1256.                 
  1257. ****************************************************************************************/
  1258. OSErr SD_JobPrintDialog(gxDialogResult *dlgResult)
  1259. {
  1260.     OSErr                     anErr;
  1261.     gxPanelSetupRecord        thePanelInfo;
  1262.     long                    headMotionSize;
  1263.     Collection                jobCollection;
  1264.     HeadMotionJobItem        theMotion;
  1265.         
  1266.     // Get a reference to the job's collection
  1267.     jobCollection = GXGetJobCollection( GXGetJob() );
  1268.     
  1269.     // See if the head motion collection item exists.  It the item already exists, then
  1270.     // we'll use the last settings.
  1271.  
  1272.     headMotionSize = sizeof(HeadMotionJobItem);
  1273.     anErr = GetCollectionItem (jobCollection,
  1274.                                         kDrvrCreatorType, 
  1275.                                         kHeadMotionItemIndex, 
  1276.                                            &headMotionSize,
  1277.                                            &theMotion);
  1278.                                         
  1279.     if (anErr == collectionItemNotFoundErr)    // T => Item doesn't exist; add it
  1280.     {
  1281.         theMotion.direction = doUnidirectional;
  1282.         
  1283.         anErr = AddCollectionItem(    GXGetJobCollection(GXGetJob()), 
  1284.                                     kDrvrCreatorType, 
  1285.                                     kHeadMotionItemIndex, 
  1286.                                     sizeof(HeadMotionJobItem),
  1287.                                     &theMotion);
  1288.         require(anErr == noErr, AddCollectionItem);
  1289.     }
  1290.     else
  1291.         require(anErr == noErr, CantGetCollection);
  1292.  
  1293.     // Before allowing the Printing Manager to display the dialog, we must first add
  1294.     // our panel to the dialog.  We do this by appropriately filling in the gxPanelSetupRecord
  1295.     // and then telling the Printing Manager to add our panel to the dialog.
  1296.     
  1297.     // Initialize the dialog panel structure
  1298.     thePanelInfo.panelResId            = kLQOptionsPanl;        //    Resource ID of the 'panl' resource
  1299.     thePanelInfo.resourceRefNum    = GXGetMessageHandlerResFile();
  1300.     thePanelInfo.refCon                = 0;
  1301.     thePanelInfo.panelKind            = gxDriverPanel;
  1302.     
  1303.     // Add the dialog panel to the Print dialog
  1304.     
  1305.     GXSetupDialogPanel(&thePanelInfo);
  1306.     anErr = GXGetJobError( GXGetJob() );
  1307.     require(anErr == noErr, SetupDialogPanel);
  1308.  
  1309.     // Now we let the dialog be displayed. 
  1310.  
  1311.     anErr = Forward_GXJobPrintDialog(dlgResult);
  1312.     check(anErr == noErr);
  1313.     
  1314.     
  1315. /******* Clean-up *******/
  1316.  
  1317. Forward_GXJobPrintDialog:
  1318. SetupDialogPanel:
  1319. CantGetCollection:
  1320. AddCollectionItem:
  1321.     return(anErr);
  1322. }
  1323. /* SD_JobPrintDialog */
  1324.  
  1325.  
  1326. /****************************************************************************************
  1327.  
  1328.                             SD_JobFormatModeQuery
  1329.                             
  1330.     function:
  1331.                 This routine is called when an application calls JobFormatModeQuery to determine
  1332.                 the format modes that are available from the driver.  This message gives the 
  1333.                 driver the opportunity to determine the type of format mode query the driver
  1334.                 is requesting and responds to it with the appropriate data.
  1335.                 
  1336.     parameters:                
  1337.                 theQuery        type of query to perform
  1338.                 srcData        source data (varies depending upon the type of query)
  1339.                 dstData        destination data (varies depending upon the type of query)
  1340.                 
  1341.     returns:
  1342.                 OSErr
  1343.                 
  1344. ****************************************************************************************/
  1345. OSErr SD_JobFormatModeQuery(gxQueryType theQuery, void *srcData, void *dstData)
  1346. {
  1347.     OSErr        anErr = noErr;
  1348.     Handle    theFonts;
  1349.     Handle    theStyles;
  1350.     
  1351.     check(dstData != nil);
  1352.     
  1353.     // What type of query is being requested?
  1354.     switch(theQuery) 
  1355.     {
  1356.         case gxSetStyleJobFormatCommonStyleQuery:
  1357.         {
  1358.             char                *pStyleName;
  1359.  
  1360.             // Fetch the list of supported styles
  1361.             
  1362.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
  1363.             require(anErr == noErr, FailedToLoadStyles1);
  1364.             
  1365.             HNoPurge(theStyles);
  1366.             HLock(theStyles);
  1367.             
  1368.             // Determine which style is being referenced and set the corresponding gxStyle (only 2 styles
  1369.             // are currently supported)
  1370.             
  1371.             if (**((short **) theStyles) == 2)    //    T => We have the correct number of styles
  1372.             {
  1373.                 char        whichFace = 0;
  1374.                 
  1375.                 pStyleName = ((char *) *theStyles) + sizeof(short); 
  1376.                 
  1377.                 if ( IUCompString(pStyleName, (char *) srcData) == 0 )    //    T => They want bold face
  1378.                 {
  1379.                     whichFace = bold;
  1380.                 }
  1381.                 else
  1382.                 {
  1383.                     // Point to the next name in the list
  1384.                     pStyleName += *pStyleName + 1;
  1385.  
  1386.                     if ( IUCompString(pStyleName, (char *) srcData) == 0 )    //    T => They want underline face
  1387.                     {
  1388.                         whichFace = underline;
  1389.                     }
  1390.                 }
  1391.  
  1392.                 //    If the client specified a valid face, set it now
  1393.                 if (whichFace != 0)
  1394.                 {
  1395.                     SetStyleCommonFace((gxStyle) dstData, GetStyleCommonFace((gxStyle) dstData) | whichFace);
  1396.                 }
  1397.             }
  1398.             // else - something is wrong with our resource
  1399.             
  1400.             // Dump the temporary handle
  1401.             DisposHandle(theStyles);
  1402.             
  1403.             break;
  1404.         }
  1405.             
  1406.         case gxGetJobFormatFontCommonStylesQuery:
  1407.         {
  1408.             short                numStyles;
  1409.             short                i;
  1410.             char                *pStyleName;
  1411.  
  1412.             // Fetch the list of supported styles
  1413.             
  1414.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
  1415.             require(anErr == noErr, FailedToLoadStyles2);
  1416.             
  1417.             HNoPurge(theStyles);
  1418.             HLock(theStyles);
  1419.             
  1420.             // Determine the number of styles in the list
  1421.             numStyles = **((short **) theStyles);
  1422.  
  1423.             if (*(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on the styles
  1424.                 SetHandleSize(*(Handle *)dstData, sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
  1425.             else
  1426.                 *(Handle *)dstData = NewHandle(sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
  1427.             
  1428.             anErr = MemError();
  1429.             require(anErr == noErr, StyleTableResizeFailed);
  1430.             
  1431.             // Now extract the name of each of the supported fonts
  1432.             
  1433.             for (i = 1, pStyleName = ((char *) *theStyles) + sizeof(short); i <= numStyles; ++i, pStyleName += *pStyleName + 1)
  1434.             {
  1435.                 BlockMove(pStyleName, (*((gxStyleNameTableHdl) *(Handle *)dstData))->styleNames[i - 1], *pStyleName + 1);
  1436.             }
  1437.             
  1438.             (*((gxStyleNameTableHdl) *(Handle *)dstData))->numStyleNames = numStyles;
  1439.             
  1440.             // Dump the temporary handle
  1441.             DisposHandle(theStyles);
  1442.             
  1443.             break;
  1444.         }
  1445.             
  1446.         case gxGetJobFormatLineConstraintQuery:            //    This type of query is not supported
  1447.             if (*(Handle *)dstData != nil)
  1448.                 SetHandleSize(*(Handle *)dstData, 0);        // Don't return any data
  1449.             break;
  1450.             
  1451.         case gxGetJobFormatFontsQuery:
  1452.         {
  1453.             short                numFonts;
  1454.             short                i;
  1455.             char                *pFontName;
  1456.  
  1457.             // Fetch the list of supported fonts
  1458.             
  1459.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeFontsID, &theFonts);
  1460.             require(anErr == noErr, FailedToLoadFonts);
  1461.             
  1462.             HNoPurge(theFonts);
  1463.             HLock(theFonts);
  1464.             
  1465.             // Determine the number of fonts in the list
  1466.             numFonts = **((short **) theFonts);
  1467.  
  1468.             if (*(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on the fonts
  1469.                 SetHandleSize(*(Handle *)dstData, sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
  1470.             else
  1471.                 *(Handle *)dstData = NewHandle(sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
  1472.             
  1473.             anErr = MemError();
  1474.             require(anErr == noErr, FontTableResizeFailed);
  1475.             
  1476.             // Now generate a reference to each of the supported fonts
  1477.             
  1478.             for (i = 1, pFontName = ((char *) *theFonts) + sizeof(short); i <= numFonts; ++i, pFontName += *pFontName + 1)
  1479.             {
  1480.                 gxFont        thisFont;
  1481.                 gxFontTable    *pFontTable;
  1482.             
  1483.                 thisFont = FindPNameFont(gxFullFontName, pFontName);
  1484.                 
  1485.                 pFontTable = *((gxFontTableHdl) *(Handle *)dstData);
  1486.                 pFontTable->fonts[i - 1] = thisFont;
  1487.             }
  1488.             
  1489.             (*((gxFontTableHdl) *(Handle *)dstData))->numFonts = numFonts;
  1490.             
  1491.             // Dump the temporary handle
  1492.             DisposHandle(theFonts);
  1493.  
  1494.             break;
  1495.         }
  1496.             
  1497.         case gxGetJobFormatFontConstraintQuery:
  1498.         {
  1499.             gxPositionConstraintTable        *pPositionTable;
  1500.             
  1501.             if ( *(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on position constraints
  1502.                 SetHandleSize(*(Handle *)dstData, sizeof(gxPositionConstraintTable) + sizeof(Fixed));
  1503.             else
  1504.                 *(Handle *)dstData = NewHandle( sizeof(gxPositionConstraintTable) + sizeof(Fixed) );
  1505.             
  1506.             pPositionTable = *((gxPositionConstraintTableHdl) *(Handle *)dstData);
  1507.             
  1508.             pPositionTable->phase.x     = 0;                //    Start at the top left corner of the page
  1509.             pPositionTable->phase.y     = 0;
  1510.             pPositionTable->offset.x     = ff(12);        // Indent from the top left by a six lines per inch margin
  1511.             pPositionTable->offset.y     = ff(12);         
  1512.             pPositionTable->numSizes     = 2;                // Two gxFont sizes supported
  1513.             pPositionTable->sizes[0]     = ff(10);         // 10 pitch
  1514.             pPositionTable->sizes[1]     = ff(12);         // 12 pitch
  1515.             
  1516.             break;
  1517.         }
  1518.     } // switch
  1519.     
  1520.     return(anErr);
  1521.     
  1522.  
  1523. /******* Clean-up *******/
  1524.  
  1525. StyleTableResizeFailed:
  1526.     DisposHandle((Handle) theStyles);
  1527.     return(anErr);
  1528.  
  1529. FontTableResizeFailed:
  1530.     DisposHandle((Handle) theFonts);
  1531.  
  1532. FailedToLoadStyles1:
  1533. FailedToLoadStyles2:
  1534. FailedToLoadFonts:
  1535.     return(anErr);
  1536. }
  1537. /* SD_JobFormatModeQuery */
  1538.  
  1539.  
  1540. /****************************************************************************************
  1541.  
  1542.                             SD_OpenConnection
  1543.                             
  1544.     function:
  1545.                 This routine is called when the Printing Manager sends the OpenConnection
  1546.                 message.  We take this opportunity to open a connection to the printer and
  1547.                 query the printer to determine its configuration (e.g. color ribbon, trays, etc.).
  1548.                 We then save the configuration information in the desktop printer file.
  1549.                 
  1550.     parameters:        
  1551.                 None
  1552.                 
  1553.     returns:
  1554.                 OSErr
  1555.     
  1556. ****************************************************************************************/
  1557. OSErr SD_OpenConnection(void)
  1558. {
  1559.     OSErr                anErr;
  1560.  
  1561.     // Try to open the connection
  1562.     
  1563.     anErr = Forward_GXOpenConnection();
  1564.     require(anErr == noErr, Forward_GXOpenConnection);
  1565.     
  1566.     // Query the printer so we can update the configuration information
  1567.     
  1568.     anErr = UpdateDTPConfigInfo();
  1569.     require(anErr == noErr, UpdateDTPConfigInfo);
  1570.     
  1571.     return(anErr);
  1572.     
  1573.     
  1574. /******* Clean-up *******/
  1575.  
  1576. UpdateDTPConfigInfo:
  1577.     Send_GXCleanupOpenConnection();
  1578.     
  1579. Forward_GXOpenConnection:
  1580.     return(anErr);
  1581. }
  1582. /* SD_OpenConnection */
  1583.  
  1584.  
  1585. /****************************************************************************************
  1586.  
  1587.                             SD_CleanupOpenConnection
  1588.                             
  1589.     function:
  1590.                 This routine is called when the Printing Manager sends the CleanupOpenConnection
  1591.                 message.  It's initiated by our SD_OpenConnection routine when we cannot query
  1592.                 the printer after opening the connection.  We simply forward the message along to
  1593.                 allow others in the message chain to cleanup.
  1594.                 
  1595.     parameters:        
  1596.                 None
  1597.                 
  1598.     returns:
  1599.                 OSErr
  1600.     
  1601. ****************************************************************************************/
  1602. void SD_CleanupOpenConnection(void)
  1603. {
  1604.     // Just forward along the message
  1605.     Forward_GXCleanupOpenConnection();
  1606. }
  1607. /* SD_CleanupOpenConnection */
  1608.  
  1609.  
  1610. /****************************************************************************************
  1611.  
  1612.                             SD_StartSendPage
  1613.                             
  1614.     function:
  1615.                 This routine is called by the Printing Manager to signal the start of sending
  1616.                 a new page to the printer.  If it's a manual feed job, then we alert the user
  1617.                 to make sure the paper is in the printer.  If the printer has trays attached,
  1618.                 then this routine determines from which tray to feed the paper and then sends
  1619.                 the appropriate tray selection command to the printer.  The tray to pull the
  1620.                 paper from has already been determined by this time by the Universal Driver.
  1621.                 The Job collection contains the index of the tray to pull from.
  1622.                 
  1623.     parameters:                
  1624.                 pageFormat        format for the page to print
  1625.  
  1626.     returns:
  1627.                 OSErr
  1628.     
  1629. ****************************************************************************************/
  1630. OSErr SD_StartSendPage (gxFormat pageFormat)
  1631. {
  1632.     OSErr                anErr;
  1633.     Boolean                manualFeed;
  1634.     gxPaperType            thePaperType;
  1635.     gxStatusRecord        *pStatus;
  1636.     SpecGlobalsHdl         hGlobals = GetMessageHandlerInstanceContext();
  1637.     
  1638.     // Determine if this is a manual feed job 
  1639.  
  1640.     thePaperType = GXGetFormatPaperType(pageFormat);
  1641.     anErr = IsManualFeedPaperType(thePaperType, &manualFeed);
  1642.     require(anErr == noErr, IsManualFeedPaperType);
  1643.     
  1644.     if (manualFeed)    //    T => Alert the user to place the paper into the printer
  1645.     {
  1646.         gxManualFeedRecord    *mfeedInfo;
  1647.  
  1648.         // Wait for all IO to complete, so that we can correctly tell the user what to do.
  1649.         // Since the WriteData message makes sure all data is flushed before performing the
  1650.         // IO, this call insures that pending IO is complete.
  1651.  
  1652.         anErr = Send_GXWriteData(nil, 0);
  1653.         nrequire(anErr, FlushAllData);
  1654.  
  1655.         // Now we set-up to alert the user to put paper into the printer
  1656.     
  1657.         pStatus = (gxStatusRecord *) NewPtrClear(sizeof(gxStatusRecord) + sizeof(gxManualFeedRecord));
  1658.         anErr = MemError();
  1659.         require(anErr == noErr, NewPtrClear);
  1660.     
  1661.         // Initialize the appropriate fields within the status record 
  1662.         
  1663.         pStatus->statResId         = gxUnivAlertStatusResourceId;
  1664.         pStatus->statResIndex     = gxUnivManualFeedIndex;
  1665.         pStatus->bufferLen         = sizeof(gxManualFeedRecord);
  1666.  
  1667.         mfeedInfo = (gxManualFeedRecord *) &pStatus->statusBuffer;
  1668.         mfeedInfo->canAutoFeed = true;
  1669.         GXGetPaperTypeName(thePaperType, mfeedInfo->paperTypeName);
  1670.  
  1671.         // Now display the alert to the user. Continue alerting until the user clicks OK, he cancels
  1672.         // printing, or some other fatal error happens
  1673.         do
  1674.         {
  1675.             // Issue the alert to the user
  1676.             anErr = GXAlertTheUser(pStatus);
  1677.         }
  1678.         while ( (anErr == noErr) && (pStatus->dialogResult == nil) );
  1679.         
  1680.         // Based upon the users response, we continue, cancel, or switch to auto-feed
  1681.         
  1682.         switch (pStatus->dialogResult)
  1683.         {
  1684.             case ok:                        // Assume the user loaded the paper 
  1685.                 break;
  1686.                 
  1687.             case cancel:                // User cancelled the job; make sure the error code is set
  1688.                 anErr = gxPrUserAbortErr;
  1689.                 break;
  1690.                 
  1691.             case gxAutoFeedButtonId:    // User wishes to do the remainder of the job with auto-feed. Update job to 
  1692.                                             // reflect auto-feed. 
  1693.                 
  1694.                 (void) UpdatePaperFeed(GXGetJob(), true);
  1695.                 break;
  1696.         }
  1697.         
  1698.         // Dump the status record
  1699.         DisposPtr((Ptr) pStatus);
  1700.     }
  1701.     
  1702.     require(anErr == noErr, UserAborted);
  1703.     
  1704.     // At this point we determine if there are trays attached, and if so, we need
  1705.     // to issue a command to the printer to select from the proper tray.
  1706.     
  1707.     if ( PrinterHasTrays() > 0 )    //    T => gxPrinter does have trays attached
  1708.     {
  1709.         gxTrayIndex                    whichTray;
  1710.         long                        itemSize;
  1711.         char                        cmndBuff[3];
  1712.         TraySettingsJobItem            oldAppTraySettings;
  1713.         
  1714.         // We first determine if we're printing from an old application or a new application because
  1715.         // the setting of which tray to use will be determined from different information. To see if
  1716.         // we are printing an old app. document, we look for the kTraySettingsItemIndex collection item.
  1717.         
  1718.         itemSize = sizeof(TraySettingsJobItem);
  1719.         if ( GetCollectionItem( GXGetJobCollection(GXGetJob()), kDrvrCreatorType, kTraySettingsItemIndex, &itemSize, &oldAppTraySettings) == noErr )
  1720.         {
  1721.             if ( (*hGlobals)->pagePrinting == 1 )    //    T => Printing the first page
  1722.             {
  1723.                 whichTray = oldAppTraySettings.firstPageFromTray - 1;        //    Must be zero based
  1724.             }
  1725.             else    //    T => Printing some other page
  1726.             {
  1727.                 whichTray = oldAppTraySettings.remainingFromTray - 1;        //    Must be zero based
  1728.             }
  1729.         }
  1730.         else    //    T => New app so get tray settings from the 'tray' collection item
  1731.         {
  1732.             // The 'tray' collection item within the job collection specifies which tray to select
  1733.             // the paper from.
  1734.             
  1735.             itemSize = sizeof(gxTrayIndex);
  1736.             if ( GetCollectionItem( GXGetJobCollection(GXGetJob()), gxTrayFeedTag, gxPrintingTagID, &itemSize, &whichTray) != noErr )
  1737.                 whichTray = 0;        // Use default tray if we can't get the collection item
  1738.             else
  1739.                 whichTray -= 1;        // Must be zero based
  1740.         }
  1741.         
  1742.         // Compose the tray selection command
  1743.         
  1744.         cmndBuff[0] = kEscape;
  1745.         cmndBuff[1] = '@';
  1746.         cmndBuff[2] = whichTray + 0x30;        // Force to an ACSII number
  1747.         
  1748.         // Send the command to the printer
  1749.         anErr = Send_GXBufferData(cmndBuff, 3, gxNoBufferOptions);
  1750.         require(anErr == noErr, BufferData);        
  1751.     }
  1752.     
  1753.     // Update the status information to tell the user that we're sending data to the printer
  1754.     
  1755.     anErr = GXReportStatus(kDriverStatusID, kSendingPartOfPageStatIdx);
  1756.     require(anErr == noErr, GXReportStatus);
  1757.  
  1758.     // Now forward the message to others in the chain
  1759.     
  1760.     anErr = Forward_GXStartSendPage(pageFormat);
  1761.     check(anErr == noErr);
  1762.     
  1763.     
  1764. /******* Cleanup *******/
  1765.  
  1766. GXReportStatus:
  1767. BufferData:
  1768. UserAborted:
  1769. NewPtrClear:
  1770. FlushAllData:
  1771. IsManualFeedPaperType:
  1772.     return(anErr);
  1773. }
  1774. /* SD_StartSendPage */
  1775.  
  1776.  
  1777. /****************************************************************************************
  1778.  
  1779.                             SD_ImagePage
  1780.                             
  1781.     function:
  1782.                 This routine is called by the Printing Manager to signal the start of imaging
  1783.                 a new page to the printer.  We take this opportunity to remember which page is
  1784.                 being printed.  This inforamtion is later used by SD_StartSendPage to control
  1785.                 the input tray selection for documents which are printed from old applications.
  1786.                 
  1787.     parameters:                
  1788.                 theFormat        format for the page being rendered
  1789.                 theShape            gxShape representing the page
  1790.                 pageInfo            information about the page being rendered
  1791.                 imageData        pointer to the raster image data
  1792.  
  1793.     returns:
  1794.                 OSErr
  1795.     
  1796. ****************************************************************************************/
  1797. OSErr SD_ImagePage (        gxSpoolFile                theFile, 
  1798.                             long                     pageNumber, 
  1799.                             gxFormat                theFormat, 
  1800.                             gxRasterImageDataHdl     imageData)
  1801. {
  1802.     OSErr                    anErr;
  1803.     SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  1804.  
  1805.     // Remember which page of the document we're currently imaging
  1806.     (*hGlobals)->pagePrinting = pageNumber;
  1807.     
  1808.     // Send the message along to others in the chain
  1809.     anErr = Forward_GXImagePage(theFile, pageNumber, theFormat, imageData);
  1810.     check(anErr == noErr);
  1811.     
  1812.     return(anErr);
  1813. }
  1814. /* SD_ImagePage */
  1815.  
  1816.  
  1817. /****************************************************************************************
  1818.  
  1819.                             SD_RenderPage
  1820.                             
  1821.     function:
  1822.                 This routine is called by the Printing Manager to signal the start of sending
  1823.                 a new page to the printer.  If it's a manual feed job, then we alert the user
  1824.                 to make sure the paper is in the printer.  Next we set the printer's left margin
  1825.                 and then we're set to begin printing the page.
  1826.                 
  1827.     parameters:                
  1828.                 theFormat        format for the page being rendered
  1829.                 theShape            gxShape representing the page
  1830.                 pageInfo            information about the page being rendered
  1831.                 imageData        pointer to the raster image data
  1832.  
  1833.     returns:
  1834.                 OSErr
  1835.     
  1836. ****************************************************************************************/
  1837. OSErr SD_RenderPage (gxFormat                    theFormat, 
  1838.                     gxShape                        thePage, 
  1839.                     gxPageInfoRecord            *pageInfo, 
  1840.                     gxRasterImageDataHdl     imageData)
  1841. {
  1842.     OSErr                    anErr;
  1843.     SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  1844.     gxRectangle            paperSize;
  1845.     
  1846.     // Find out how big our paper is
  1847.     GXGetFormatDimensions(theFormat, nil, &paperSize);
  1848.     
  1849.     // Determine the left margin (in pixels)
  1850.     {
  1851.         SpecGlobalsPtr            pGlobals;
  1852.         gxRasterImageDataPtr    pImageData;
  1853.  
  1854.         pImageData = *imageData;
  1855.         pGlobals = *hGlobals;
  1856.         if ( -(paperSize.left) < ff(18) )    // T => IW LQ's can't go tighter than .25 inch
  1857.             paperSize.left = -(ff(18));        
  1858.         
  1859.         pGlobals->leftMargin = FixedToInt( FixMul(-paperSize.left, FixDiv(pImageData->hImageRes, ff(72)) ) );
  1860.     }
  1861.  
  1862.     // If not text mode, image the page the normal raster way (via SD_RasterPackageBitmap).  We
  1863.     // must however set the size of the page and position the paper (with line feeds) to get to
  1864.     // the proper "top-of-form".
  1865.     
  1866.     if ( GXGetJobFormatMode(GXGetJob()) != gxTextJobFormatMode ) 
  1867.     {
  1868.         Str255            formLength;            // should be more than big enough for form skipping
  1869.         char                aNumber[8];
  1870.         char                len = 0;
  1871.         short                formLen;                // form length (in 144 dpi)
  1872.         short                i;
  1873.         
  1874.         // Force the current line position to be the top of form (assumes the user has positioned the 
  1875.         // paper properly by this time)
  1876.         
  1877.         formLength[len++] = kEscape;
  1878.         formLength[len++] = 'v';
  1879.  
  1880.         // Now we want to skip down the page past the top margin.  This will put us in a position to
  1881.         // output the first bands of data.
  1882.         
  1883.         formLen = FixedToInt( FixMul(-paperSize.top, ff(2)) );                    // length is set in 144 dpi
  1884.         if (formLen > 0)
  1885.         {
  1886.             // send multiples of 99 since this is the maximum line feed spacing we can have
  1887.             if (formLen >= 99)
  1888.             {
  1889.                 formLength[len++] = kEscape;
  1890.                 formLength[len++] = 'T';
  1891.                 formLength[len++] = '9';
  1892.                 formLength[len++] = '9';
  1893.                 do
  1894.                 {
  1895.                     formLength[len++] = kLineFeed;        // line feed
  1896.                     
  1897.                     formLen -= 99;
  1898.                 }
  1899.                 while (formLen >= 99);
  1900.             }
  1901.                 
  1902.             // Send remaining line feeds to position to the top of the printable page
  1903.             if (formLen > 0)
  1904.             {
  1905.                 formLength[len++] = kEscape;
  1906.                 formLength[len++] = 'T';
  1907.                 NumToString(formLen, aNumber);
  1908.                 if ( Length(aNumber) == 1 )
  1909.                 {
  1910.                     formLength[len++] = '0';
  1911.                     formLength[len++] = aNumber[1];
  1912.                 }
  1913.                 else
  1914.                 {
  1915.                     formLength[len++] = aNumber[1];
  1916.                     formLength[len++] = aNumber[2];
  1917.                 }
  1918.                 formLength[len++] = kLineFeed;        // line feed
  1919.             }
  1920.         }
  1921.         
  1922.         // Now we must specify the paper length based upon the paper size asociated with the format
  1923.         
  1924.         formLength[len++] = kEscape;
  1925.         formLength[len++] = 'H';
  1926.  
  1927.         formLen = FixedToInt( FixMul(paperSize.bottom - paperSize.top, ff(2)) );    // length is set in 144 dpi
  1928.         NumToString(formLen, aNumber);
  1929.         for (i = 0; i < 4-aNumber[0]; ++i)
  1930.             formLength[len++] = '0';
  1931.         for (i = 1; i <= aNumber[0]; ++i)
  1932.             formLength[len++] = aNumber[i];
  1933.  
  1934.         // Send out the line feeds and the paper size specifier
  1935.         anErr = Send_GXBufferData(&formLength[0], len, gxNoBufferOptions);
  1936.         require(anErr == noErr, SetFormLength);        
  1937.     
  1938.         // Now forward the message to others in the chain
  1939.         
  1940.         anErr = Forward_GXRenderPage(theFormat, thePage, pageInfo, imageData);
  1941.         require(anErr == noErr, Forward_GXRenderPage);
  1942.     } 
  1943.     else    //    T => Doing draft (i.e. direct mode) print job; we do all the rendering
  1944.     {
  1945.         anErr = PrintPageInDraftMode(thePage, imageData);
  1946.     }
  1947.     
  1948.     
  1949. /******* Cleanup *******/
  1950.  
  1951. SetFormLength:
  1952. Forward_GXRenderPage:
  1953.     return(anErr);
  1954. }
  1955. /* SD_RenderPage */
  1956.  
  1957.  
  1958. /****************************************************************************************
  1959.  
  1960.                             SD_DefaultPrinter
  1961.                             
  1962.     function:
  1963.                 This routine is called when a new printer object is being created as a
  1964.                 result of someone having called NewJob.  This message gives the driver the
  1965.                 opportunity to add any information we want to the new printer object.  In
  1966.                 this case, we add a new black and white gxViewDevice to the printer object 
  1967.                 which will allow the client application to format a document for this 
  1968.                 specific device at 216 dpi.  If the printer has a color ribbon attachment,
  1969.                 then we create a second view device at 216 dpi which supports eight
  1970.                 colors.
  1971.                 
  1972.     parameters:                
  1973.                 thePrinter        the newly allocated printer object
  1974.                 
  1975.     returns:
  1976.                 OSErr
  1977.                 
  1978. ****************************************************************************************/
  1979. OSErr SD_DefaultPrinter(gxPrinter thePrinter)
  1980. {
  1981.     OSErr             anErr;
  1982.     gxSetColor        theColors[8];
  1983.     gxSetColor        *pColor;
  1984.     
  1985.     // First we let others in the chain default the printer object before we do. 
  1986.  
  1987.     anErr = Forward_GXDefaultPrinter(thePrinter);
  1988.     require(anErr == noErr, Forward_GXDefaultPrinter);
  1989.     
  1990.     // Add the standard black and white view device to the printer object
  1991.     
  1992.     // First set up the color set
  1993.     pColor = &theColors[0];
  1994.     pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF;            // white 
  1995.     pColor++;
  1996.     pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;            // black 
  1997.     
  1998.     // Now add the view device
  1999.     anErr = MakeNewPrinterViewDevice(thePrinter, theColors, 2);
  2000.     require(anErr == noErr, MakeBWViewDevice);
  2001.     
  2002.     // Does the printer have a color ribbon installed?
  2003.     if ( PrinterHasColorRibbon() )
  2004.     {
  2005.         // Add the standard color view device to the printer object
  2006.         
  2007.         // First set up the color set
  2008.         //
  2009.         //    Color            Index        R                G                B
  2010.         //    white            0            0xFFFF        0xFFFF        0xFFFF        
  2011.         //    yellow            1            0xFFFF        0xFFFF        0x0000
  2012.         //    magenta            2            0xFFFF        0x0000        0xFFFF
  2013.         //    red                3            0xFFFF        0x0000        0x0000
  2014.         //    cyan            4            0x0000        0xFFFF        0xFFFF
  2015.         //    green            5            0x0000        0xFFFF        0x0000
  2016.         //    blue            6            0x0000        0x0000        0xFFFF
  2017.         //    black            7            0x0000        0x0000        0x0000
  2018.  
  2019.         pColor = &theColors[0];
  2020.         pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF;                pColor++;        // white 
  2021.         pColor->rgb.red = pColor->rgb.green = 0xFFFF; pColor->rgb.blue = 0x0000;    pColor++;        // yellow 
  2022.         pColor->rgb.red = pColor->rgb.blue = 0xFFFF; pColor->rgb.green = 0x0000;    pColor++;        // magenta 
  2023.         pColor->rgb.red =0xFFFF;  pColor->rgb.blue = pColor->rgb.green = 0x0000;    pColor++;        // red 
  2024.         pColor->rgb.green = pColor->rgb.blue = 0xFFFF; pColor->rgb.red = 0x0000;    pColor++;        // cyan 
  2025.         pColor->rgb.red = pColor->rgb.blue = 0x0000; pColor->rgb.green = 0xFFFF;    pColor++;        // green 
  2026.         pColor->rgb.red = pColor->rgb.green = 0x0000; pColor->rgb.blue = 0xFFFF;    pColor++;        // blue 
  2027.         pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;                                    // black 
  2028.         
  2029.         // Now add the view device
  2030.         anErr = MakeNewPrinterViewDevice(thePrinter, theColors, 8);
  2031.         require(anErr == noErr, MakeColorViewDevice);
  2032.     }
  2033.     
  2034. /******* Clean-up *******/
  2035.  
  2036. MakeColorViewDevice:
  2037. MakeBWViewDevice:
  2038. Forward_GXDefaultPrinter:
  2039.     return(anErr);
  2040. }
  2041. /* SD_DefaultPrinter */
  2042.  
  2043. /****************************************************************************************
  2044.  
  2045.                             SD_DefaultFormat
  2046.                             
  2047.     function:
  2048.                 This routine is called when a new format is being created as a result of someone
  2049.                 having called NewFormat.  It is also called to sync up the viewDevices with the
  2050.                 collection's quality mode.
  2051.                 
  2052.     parameters:                
  2053.                 theFormat        the format being defaulted
  2054.                 
  2055.     returns:
  2056.                 OSErr
  2057.                 
  2058. ****************************************************************************************/
  2059. OSErr SD_DefaultFormat(gxFormat theFormat)
  2060. {
  2061.     OSErr    anErr;
  2062.     
  2063.     anErr = Forward_GXDefaultFormat(theFormat);
  2064.     
  2065.     // now, if the application has set up a special formatting mode, we need to update
  2066.     // the quality mode collection item (and any private ones we use)
  2067.     if (anErr == noErr)
  2068.         {
  2069.         gxPoint                    dpiPoint = {ff(72), ff(72)};
  2070.         gxMapping                vdMapping;
  2071.         gxViewDevice            selectedDevice = GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 0);
  2072.         
  2073.         if (selectedDevice != GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 1) )
  2074.             {
  2075.             GXGetViewDeviceMapping(selectedDevice, &vdMapping);
  2076.             MapPoints(&vdMapping, 1, &dpiPoint);
  2077.             
  2078.             {
  2079.             Collection                jobCollection = GXGetJobCollection(GXGetJob());
  2080.             gxQualityInfo            jobQualitySettings;
  2081.             long                    itemSize = sizeof(jobQualitySettings);
  2082.     
  2083.             anErr = GetCollectionItem(GXGetJobCollection(GXGetJob()), 
  2084.                                             gxQualityTag, gxPrintingTagID, 
  2085.                                             &itemSize, &jobQualitySettings);
  2086.             if (anErr == noErr)
  2087.                 {
  2088.                 jobQualitySettings.currentQuality = 
  2089.                     (dpiPoint.y > ff(200)) ? (jobQualitySettings.qualityCount-1) : 0;
  2090.                     
  2091.                 anErr = AddCollectionItem(jobCollection,
  2092.                                             gxQualityTag,
  2093.                                             gxPrintingTagID,
  2094.                                             itemSize,
  2095.                                             &jobQualitySettings);
  2096.                 }
  2097.             }
  2098.             
  2099.             }
  2100.  
  2101.         }
  2102.         
  2103.     return(anErr);
  2104.     
  2105. /* SD_DefaultFormat */
  2106.  
  2107. /****************************************************************************************
  2108.  
  2109.                             SD_DefaultJob
  2110.                             
  2111.     function:
  2112.                 This routine is called when a new job is being created as a result of someone
  2113.                 having called NewJob.  The driver takes this opportunity to add a default
  2114.                 head motion collection item to the job.
  2115.                 
  2116.     parameters:                
  2117.                 theJob        the job being defaulted
  2118.                 
  2119.     returns:
  2120.                 OSErr
  2121.                 
  2122. ****************************************************************************************/
  2123. OSErr SD_DefaultJob()
  2124. {
  2125.     OSErr        anErr;
  2126.     gxJob         theJob = GXGetJob();
  2127.     
  2128.     // First forward the default job message along
  2129.     anErr = Forward_GXDefaultJob();
  2130.     require(anErr == noErr, Forward_GXDefaultJob);
  2131.     
  2132.     // Add the default collection item which specifies the desired head motion.
  2133.     {
  2134.         HeadMotionJobItem        theMotion;
  2135.         
  2136.         theMotion.direction = doUnidirectional;
  2137.         
  2138.         anErr = AddCollectionItem(    GXGetJobCollection(theJob), 
  2139.                                             kDrvrCreatorType, 
  2140.                                             kHeadMotionItemIndex, 
  2141.                                             sizeof(HeadMotionJobItem),
  2142.                                             &theMotion);
  2143.         check(anErr == noErr);
  2144.     }
  2145.  
  2146.  
  2147. /******* Clean-up *******/
  2148.  
  2149. Forward_GXDefaultJob:
  2150.     return(anErr);
  2151. }
  2152. /* SD_DefaultJob */
  2153.  
  2154.  
  2155. /****************************************************************************************
  2156.  
  2157.                             SD_SetupImageData
  2158.                             
  2159.     function:
  2160.                 This routine is called when the Printing Manager wants us to initialize any
  2161.                 constant data that's used to image the entire job.  This driver takes this
  2162.                 opportunity to massage the raster image data 
  2163.                 
  2164.     parameters:                
  2165.                 hImageData        Handle to the raster imaging data
  2166.     returns:
  2167.                 OSErr
  2168.     
  2169. ****************************************************************************************/
  2170. OSErr SD_SetupImageData(gxRasterImageDataHdl hImageData)
  2171. {
  2172.     OSErr                    anErr;
  2173.     Boolean                 isJobNotFinalQuality;
  2174.     Boolean                    isTextJobFormatMode;
  2175.     gxRasterImageDataPtr    pImageData;
  2176.     HeadMotionJobItem        theMotion;
  2177.     long                    headMotionSize;
  2178.     gxJob                    theJob = GXGetJob();
  2179.  
  2180.     // Let others in the message chain do their SetupImageData function 
  2181.     anErr = Forward_GXSetupImageData(hImageData);
  2182.     require(anErr == noErr, Forward_GXSetupImageData);
  2183.     
  2184.     // Determine if we're to do "final" quality
  2185.     isJobNotFinalQuality = !JobIsBestQuality();
  2186.     
  2187.     // Fetch the head motion job collection item to determine the head motion we should be using
  2188.  
  2189.     headMotionSize = sizeof(HeadMotionJobItem);
  2190.     anErr = GetCollectionItem (GXGetJobCollection(theJob),
  2191.                                         kDrvrCreatorType,
  2192.                                         kHeadMotionItemIndex,
  2193.                                         &headMotionSize,
  2194.                                         &theMotion);
  2195.     check(anErr == noErr);
  2196.     
  2197.     if (anErr != noErr)    //    T => Default to unidirectional printing => better quality
  2198.     {
  2199.         theMotion.direction = doUnidirectional;
  2200.         anErr = noErr;
  2201.     }
  2202.  
  2203.     // Determine if we are to perform draft mode printing
  2204.     isTextJobFormatMode = ( GXGetJobFormatMode(theJob) == gxTextJobFormatMode );
  2205.     
  2206.     // If the job is not final quality or using gxTextJobFormatMode, downgrade the imaging data to lower quality
  2207.     if (isJobNotFinalQuality || isTextJobFormatMode)
  2208.     {
  2209.         pImageData = *hImageData;
  2210.                 
  2211.         // Image at 72 dpi
  2212.         pImageData->hImageRes = ff(72);
  2213.         pImageData->vImageRes = ff(72);
  2214.         
  2215.         // If we're in draft mode, we need to load the draft table to know how to print all possible characters
  2216.         if (isTextJobFormatMode)
  2217.         {
  2218.             Handle                draftTable;
  2219.             SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  2220.         
  2221.             anErr = Send_GXFetchTaggedDriverData('idft', gxPrintingDriverBaseID, &draftTable);
  2222.             require(anErr == noErr, FailedToLoadDraftTable);
  2223.             
  2224.             // Save the draft table handle in our globals
  2225.             (*hGlobals)->draftTable = draftTable;
  2226.         }
  2227.         else    //    T => We need to setup better low resolution halftones
  2228.         {
  2229.             short    plane;
  2230.             
  2231.             // Use halftones that will look better at 72 dpi resolution than our default values.
  2232.             
  2233.             // Use the same angle and frequency for all planes, because gxDispersedDot
  2234.             // won't moire on us
  2235.             for (plane = 0; plane < 4; ++plane)
  2236.             {
  2237.                 pImageData->theSetup.planeSetup[plane].planeHalftone.angle = ff(0);
  2238.                 pImageData->theSetup.planeSetup[plane].planeHalftone.frequency = ff(9);
  2239.                 pImageData->theSetup.planeSetup[plane].planeHalftone.method = gxDispersedDot;
  2240.             }
  2241.         }
  2242.         
  2243.         // Determine the StartSendPage command string to use depending upon whether the user choose birdirectional or
  2244.         // unidirectional motion.
  2245.         
  2246.         if (isJobNotFinalQuality)
  2247.         {
  2248.             // Tell the Printing Manager which "start send page" string to send to the device (the bidirectional
  2249.             // or unidirectional string)
  2250.             
  2251.             if ( theMotion.direction == doUnidirectional )
  2252.                 pImageData->packageControls.startPageStringID = kLowResUniDirID;
  2253.             else
  2254.                 pImageData->packageControls.startPageStringID = kLowResBiDirID;
  2255.         }
  2256.         
  2257.         // Update the packaging data to reflect the lower resolution
  2258.         pImageData->packagingInfo.headHeight         = 8;        // 8 pins (instead of 24)
  2259.         pImageData->packagingInfo.numberPasses     = 1;        // in 1 head pass
  2260.         pImageData->packagingInfo.passOffset         = 0;        // with no space between passes
  2261.     }
  2262.     else    //    T => Final quality job
  2263.     {
  2264.         pImageData = *hImageData;
  2265.                 
  2266.         // Tell the Printing Manager which "start send page" string to send to the device (the bidirectional
  2267.         // or unidirectional string)
  2268.         
  2269.         if ( theMotion.direction == doUnidirectional )
  2270.             pImageData->packageControls.startPageStringID = kHighResUniDirID;
  2271.         else
  2272.             pImageData->packageControls.startPageStringID = kHighResBiDirID;
  2273.  
  2274.         // image at 216 dpi
  2275.         pImageData->hImageRes = ff(216);
  2276.         pImageData->vImageRes = ff(216);
  2277.     }
  2278.     
  2279.     // If the printer doesn't have a color ribbon, set up for black and white printing
  2280.     if ( !PrinterHasColorRibbon() )
  2281.     {
  2282.         pImageData = *hImageData;
  2283.  
  2284.         // one plane, no color flags, move the halftone info up into correct position
  2285.         pImageData->theSetup.planes = 1;
  2286.         pImageData->packagingInfo.colorPasses = 1;
  2287.         pImageData->packagingInfo.packageOptions = 0;
  2288.         pImageData->theSetup.planeSetup[0] = pImageData->theSetup.planeSetup[3];
  2289.         pImageData->theSetup.planeSetup[0].planeHalftone.tinting = gxLuminanceTint;
  2290.         pImageData->theSetup.planeSetup[0].planeHalftone.tintSpace = gxRGBSpace;
  2291.     }
  2292.  
  2293.  
  2294. /******* Clean-up *******/
  2295.  
  2296. FailedToLoadDraftTable:
  2297. Forward_GXSetupImageData:
  2298.     return(anErr);
  2299. }
  2300. /* SD_SetupImageData */
  2301.  
  2302.  
  2303. /****************************************************************************************
  2304.  
  2305.                             SD_FetchTaggedData
  2306.                             
  2307.     function:
  2308.                 This routine is called by the Printing Manager when a resource is fetched
  2309.                 from some resource file.  This driver overrides this message to determine
  2310.                 when someone is fetching the 'cust' resource.  If this resource
  2311.                 is being fetched, and the job we're processing is not best quality, then
  2312.                 we lower the resolution in the 'cust' resource handle returned to be 72 dpi.
  2313.                 This ensures the translation from QuickDraw to QuickDraw GX is done at the
  2314.                 proper resolution.
  2315.                 
  2316.     parameters:    
  2317.                 rsrcType            type of the resource being retrieved
  2318.                 rsrcID            resource ID of the resource being retrieved
  2319.                 theRsrc            handle to the resource retrieved
  2320.                 owner                indicates who is issuing the request; only look at owners == 'drvr'
  2321.                 
  2322.     returns:
  2323.                 OSErr
  2324.  
  2325. ****************************************************************************************/
  2326. OSErr SD_FetchTaggedData(ResType rsrcType, short rsrcID, Handle *theRsrc, OSType owner)
  2327. {
  2328.     OSErr        anErr;
  2329.     
  2330.     if (owner == 'drvr')                                                    //    T => Fetching a driver resource
  2331.     {
  2332.         if (    (rsrcType == gxTrayCountDataType)    &&                    //    T => type is trayCountData
  2333.                 (rsrcID == gxTrayCountDataID)                            //    T => ID is trayCountData
  2334.             )
  2335.         {
  2336.             // Remap as required
  2337.             rsrcID = ((PrinterHasTrays() > 0) ? kDefaultSheetFeederRsrcID : kDefaultTrayRsrcID);
  2338.         }
  2339.         else if (    (rsrcType == gxTrayNameDataType)    &&            //    T => type is trayName
  2340.                         (rsrcID == kDefaultSheetFdrTray1NameID)    //    T => ID is trayData
  2341.             )
  2342.         {
  2343.             // Remap as required
  2344.             rsrcID = ((PrinterHasTrays() > 0) ? kDefaultSheetFdrTray1NameID : kDefaultTrayNameID);
  2345.         }
  2346.     }
  2347.     
  2348.     // First fetch the actual resource
  2349.     anErr = Forward_GXFetchTaggedData(rsrcType, rsrcID, theRsrc, owner);
  2350.     require(anErr == noErr, FetchTaggedData);
  2351.     
  2352.     if (    (owner == 'drvr')            &&        //    T => Fetching a driver resource
  2353.             (rsrcType == gxCustType)    &&        //    T => type is 'cust'
  2354.             (rsrcID == gxCustID)        &&        //    T => ID is -8192
  2355.             !JobIsBestQuality()                //    T => Doing rough output
  2356.         )
  2357.     {
  2358.         gxCustomizationHdl    custData;
  2359.         
  2360.         // Change the 'cust' resolution to specify low res translation from QuickDraw to QuickDraw GX
  2361.         (*custData)->horizontalResolution = 72;
  2362.         (*custData)->verticalResolution = 72;
  2363.     }
  2364.  
  2365.  
  2366. /******* Clean-up *******/
  2367.  
  2368. FetchTaggedData:
  2369.     return(anErr);
  2370. }
  2371. /* SD_FetchTaggedData */
  2372.  
  2373.  
  2374. /****************************************************************************************
  2375.  
  2376.                             SD_DefaultDesktopPrinter
  2377.                             
  2378.     function:
  2379.                 This routine is called by the Printing Manager when a new desktop printer is
  2380.                 created.  We take this opportunity to open a connection to the LQ printer to
  2381.                 see how it's configured.  Specifically, we determine if there are trays
  2382.                 attached and if there is a color ribbon installed.  Based upon the device query,
  2383.                 we update the desktop printer file.
  2384.                 
  2385.     parameters:    
  2386.                 printerName        Name of the printer being created
  2387.                 
  2388.     returns:
  2389.                 OSErr
  2390.  
  2391. ****************************************************************************************/
  2392. OSErr SD_DefaultDesktopPrinter(Str31 printerName)
  2393. {
  2394.     OSErr        anErr;
  2395.     
  2396.     // First let the Printing Manager create the desktop printer
  2397.     anErr = Forward_GXDefaultDesktopPrinter(printerName);
  2398.     require(anErr == noErr, DefaultDesktopPrinter);
  2399.     
  2400.     // Optional step (now removed): during creation of the printer we could open a connection
  2401.     // to get the current configuration.  However, this has the disadvantage of making the user
  2402.     // wait until the printer is available.  The user can force a configuration update by printing
  2403.     // any document to the printer (even a blank one)
  2404.     
  2405.     // Now we attempt to open a connection to the device (it will update the config. file)
  2406. //    anErr = Send_GXOpenConnection();
  2407. //    require(anErr == noErr, OpenConnection);
  2408.     
  2409.     // A side effect of opening the connection will be that we will have already updated
  2410.     // the configuration information (in the file) that specifies whether a color ribbon
  2411.     // is installed and the number of sheet feeder trays attached (if any). ## The only additional
  2412.     // thing we'd want to do here is to update the number of trays specified in the desktop
  2413.     // printer file to be the actual number of trays attached to the device.  Currently, the 
  2414.     // system assumes the number of trays attached is equivalent to the number of default
  2415.     // trays specified in our driver resources.  Though we can query the printer for the 
  2416.     // exact number of trays, we cannot update the info. in the config. file that specifies
  2417.     // the exact number of trays.  We need a RemoveTrayInfo routine.
  2418.     
  2419.     // Now we just close down the connection
  2420. //    anErr = Send_GXCloseConnection();
  2421. //    check(anErr == noErr);
  2422.  
  2423.     
  2424. /******* Clean-up *******/
  2425.  
  2426. OpenConnection:
  2427. DefaultDesktopPrinter:
  2428.     return(anErr);
  2429. }
  2430. /* SD_DefaultDesktopPrinter */
  2431.  
  2432.  
  2433. /****************************************************************************************
  2434.  
  2435.                             SD_GetDTPMenuList
  2436.                             
  2437.     function:
  2438.                 NOOP.
  2439.                 
  2440.     parameters:    
  2441.                 hMenu            Handle to the menu that's being built
  2442.                 
  2443.     returns:
  2444.                 OSErr
  2445.  
  2446. ****************************************************************************************/
  2447. OSErr SD_GetDTPMenuList(MenuHandle hMenu)
  2448. {
  2449.     return(Forward_GXGetDTPMenuList(hMenu));
  2450. }
  2451. /* SD_GetDTPMenuList */
  2452.  
  2453.  
  2454. /****************************************************************************************
  2455.  
  2456.                             SD_DTPMenuSelect
  2457.                             
  2458.     function:
  2459.                 This routine is called by the Printing Manager when a menu item in the Finder's
  2460.                 gxPrinter menu is selected.  This routine determines if the menu item selected
  2461.                 is the "Input Tray…" item. If it's, then display the dialog which lets the user
  2462.                 specify the paper in the LQ's sheet feeder if we know there are some trays
  2463.                 attached to the printer.  Otherwise, we just pass the item on to others in the chain.
  2464.                 
  2465.     parameters:    
  2466.                 itemNum        Menu item number that was selected    
  2467.                 
  2468.     returns:
  2469.                 OSErr
  2470.  
  2471. ****************************************************************************************/
  2472. OSErr SD_DTPMenuSelect(short itemNum)
  2473. {
  2474.     OSErr        anErr;
  2475.     
  2476.     if ((itemNum == gxInputTraysMenuItem) && (PrinterHasTrays() > 0))    //    T => User wants to configure the input trays
  2477.     {
  2478.         anErr = DoSheetfeederDialog();
  2479.     }
  2480.     else    //    T => We didn't process the item
  2481.     {
  2482.         // Pass the message on to others in the chain
  2483.         anErr = Forward_GXDTPMenuSelect(itemNum);
  2484.     }
  2485.     
  2486.     check(anErr == noErr);
  2487.  
  2488.     return(anErr);
  2489. }
  2490. /* SD_DTPMenuSelect */
  2491.  
  2492.  
  2493. /****************************************************************************************
  2494.  
  2495.                             SD_RasterPackageBitmap
  2496.                             
  2497.     function:
  2498.                 This routine is called by the Printing Manager when it has completed rendering
  2499.                 a single portion of a raster page and the driver should now package the data
  2500.                 and output it to the device.  This routine is called to package one complete band.
  2501.                 
  2502.                 It routine does the following:
  2503.                     
  2504.                 1)    Starts filling the buffer from buffer + bufferPos.  Remember
  2505.                     that this pointer may not be word aligned - so be careful
  2506.                     assigning things into it.
  2507.                     
  2508.                 2)    Puts a "fake" set of set margins commands at
  2509.                     the begining of the data.  Since most of the time we don't
  2510.                     know the margins, we save away the value of the bufferPos,
  2511.                     and backpatch it after we have finished with the gxBitmap.
  2512.                     
  2513.                 3)    Adds in the rotated data for your printer.  The data to stuff starts
  2514.                     at location pPackage->startRaster * pPackage->bitmapToPackage->rowBytes (startY)
  2515.                     in the pPackage->bitmapToPackage gxBitmap.  Stuffs the bits from here until
  2516.                     we reach startY + <the band size>, which is the size of our single
  2517.                     band in this resolution mode.  Increment our number by 
  2518.                     <your pass offset> + 1, which is the number of microspaces
  2519.                     we will send between head passes to form this band.   Take care
  2520.                     that we don't step off of the end of the gxBitmap in this operation,
  2521.                     since we may be called with startY at the end of the offscreen if the first part
  2522.                     of the band is white.
  2523.                     
  2524.                     colorBand contains the color band which we should be stuffing, from
  2525.                     1 to the number of color passes our printer needs (4).
  2526.                     Packs in the correct color band.  The packager will call us once
  2527.                     for each color band, and correctly handle line feeds and backward
  2528.                     line feeds to do the correct thing.  If your printer takes full
  2529.                     RGB or CYMK data, define your number of colors to be
  2530.                     1 and pack the full RGB or CYMK data with the one call.
  2531.                     
  2532.                     If you request kSendAllColors in your raster pack resource, then this
  2533.                     message will always be called for all color passes, even those that
  2534.                     do not have data on them.  For some printers, this is useful.  For the
  2535.                     case of the ImageWriter, this option is not specified, so this message
  2536.                     will only be sent for colors that actually have dirty bits within them.
  2537.                     
  2538.                 4)    Backpatches SetMargins from the saved value in step 2) now that we
  2539.                     know the margins.
  2540.                     
  2541.                 5)    Increments bufferPos by the number of bytes we have
  2542.                     added to the buffer.  Be sure to take into account the Set Margins
  2543.                     command.
  2544.  
  2545.     parameters:        
  2546.                 whatToPackage        info. about the gxBitmap whose data is to be sent to the printer
  2547.                 buffer                buffer in which to place the packaged data
  2548.                 bufferPos            position within buffer of where to place the packaged data
  2549.                 imageData            handle to the raster image data info.
  2550.                 
  2551.     returns:
  2552.                 OSErr
  2553.  
  2554. ****************************************************************************************/
  2555. OSErr SD_RasterPackageBitmap(    gxRasterPackageBitmapRec    *whatToPackage, 
  2556.                                 Ptr                         buffer,
  2557.                                 unsigned long                 *bufferPos, 
  2558.                                 gxRasterImageDataHdl        imageData)
  2559. {
  2560.     OSErr                anErr = noErr;
  2561.     ScanLinePtr            pTheScanLine;            // Pointer to the start of scan line data
  2562.     unsigned short        firstDirty;                // First dirty pixel
  2563.     Boolean                bandIsDirty;            // Is this band dirty?
  2564.     unsigned short        whichCol;                // Index into the scan line data of where to place the next data bytes
  2565.     unsigned short        x;                            
  2566.     unsigned long        tempColumn;                // Placeholder for the column of data we're currently assembling
  2567.                                                         //    for 72 dpi:     only high order byte is used
  2568.                                                         //    for 216 dpi:    highest order three bytes are used
  2569.     Ptr                    basePtr;                    // Pointer to current X byte
  2570.     unsigned char        outputMask;                // Mask of bit to set in rotated image
  2571.     unsigned char        inputMask;                // Mask of bit to look at in X
  2572.     unsigned short        yPointerOffset;        // Increment pointer by this to get to next scanline
  2573.     unsigned short        endY;                        //    Last scan line to examine (top-to-bottom)
  2574.     unsigned short        endX;                        //    Last pixel column to examine (left-to-right)
  2575.     unsigned short        incrY;                    //    Number of scan lines to increment by when advancing to the next scan line
  2576.     short                bytesPerBand;            //    Number of bytes in a single band (1 for 72 dpi, 3 for 216 dpi)
  2577.             
  2578.  
  2579.     // Determine the number of bytes that are in a single band 
  2580.     if ( (*imageData)->hImageRes == ff(72) )    //    T => Low resolution output
  2581.         bytesPerBand = 1;
  2582.     else
  2583.         bytesPerBand = 3;
  2584.     
  2585.     //    Overlay a scan line structure on the buffer we're filling in 
  2586.     pTheScanLine = (ScanLinePtr) (buffer + *bufferPos);
  2587.     
  2588.     // Set color mode for this scan line, if needed 
  2589.     
  2590.     pTheScanLine->cColorEscape = kEscape;
  2591.     pTheScanLine->cSetColorCommand = kSetColorCommand;
  2592.     
  2593.     if ( (*imageData)->packagingInfo.colorPasses == 4 )    //    T => Doing four pass color output
  2594.     {
  2595.         switch (whatToPackage->colorBand)    //    Determine which color to select
  2596.         {
  2597.             case 1: // yellow
  2598.                 pTheScanLine->cColor    = '1';
  2599.                 break;
  2600.                 
  2601.             case 2: // magenta
  2602.                 pTheScanLine->cColor    = '2';
  2603.                 break;
  2604.  
  2605.             case 3: // cyan
  2606.                 pTheScanLine->cColor    = '3';
  2607.                 break;
  2608.                 
  2609.             case 4: // black
  2610.                 pTheScanLine->cColor    = '0';
  2611.                 break;
  2612.         }
  2613.     }
  2614.     else    //    T => Just doing black and white printing; select the color black
  2615.         pTheScanLine->cColor = '0';
  2616.  
  2617.     // We start out with no dirty bits
  2618.     firstDirty = 0;
  2619.     bandIsDirty = false;
  2620.     
  2621.     // Set our array index to zero
  2622.     whichCol = 0;
  2623.     
  2624.     // Get the byte pointer for the start of this color band
  2625.     basePtr = whatToPackage->bitmapToPackage->image;
  2626.     
  2627.     // Get the byte pointer for the start of the first scan line
  2628.     basePtr += whatToPackage->startRaster * whatToPackage->bitmapToPackage->rowBytes;
  2629.             
  2630.     // Save away loop invariants
  2631.     
  2632.     endY = whatToPackage->startRaster + (*imageData)->packagingInfo.headHeight;    // Ending Y scan line
  2633.     incrY = (*imageData)->packagingInfo.passOffset + 1;                                    // Number of scanlines to increment by
  2634.     endX = whatToPackage->dirtyRect.right;                                                        // Ending X pos
  2635.     yPointerOffset = incrY * whatToPackage->bitmapToPackage->rowBytes;                // amount to add to the input pointer to move to the next scanline
  2636.  
  2637.     // If the ending position is too large for the gxBitmap we have been given,
  2638.     //truncate it, so that we don't print garbage
  2639.  
  2640.     if (endY > whatToPackage->bitmapToPackage->height)
  2641.          endY = whatToPackage->bitmapToPackage->height;
  2642.     
  2643.     // Start with the first bit in the byte sub-band
  2644.     inputMask = 0x80;
  2645.  
  2646.     // For the entire width of the scan line, move a rolling mask along in the
  2647.     // X direction, rotating up 8 or 24 bits of Y data per column.
  2648.     
  2649.     for (x = 0; x < endX; x++)
  2650.     {        
  2651.         Ptr    thePtr;
  2652.  
  2653.         // The bits in this column are clear to begin with
  2654.         tempColumn = 0;
  2655.         
  2656.         // Which byte(s) to look at in the input buffer
  2657.         thePtr = basePtr;
  2658.         
  2659.         // For the number of bytes in a single band, scan through each single  
  2660.         // byte sub-band, setting each of the 8 bits = the bit in that scan line
  2661.         {
  2662.             short                bitsPerByte;
  2663.             short                byteSubBand = bytesPerBand;
  2664.             unsigned char        *currByte = (unsigned char *) &tempColumn;
  2665.             short                currYPos;
  2666.             
  2667.             currYPos = whatToPackage->startRaster;
  2668.             
  2669.             do
  2670.             {
  2671.                 // Where to place the bit in the output. The LQ takes the bit pattern upside down.
  2672.                 outputMask = 0x01;
  2673.         
  2674.                 bitsPerByte = 8;
  2675.                 while ( (bitsPerByte > 0) && (currYPos < endY) )
  2676.                 {
  2677.                     // If we have a bit turned on in the input, rotate it into the output
  2678.                     if ( ((*thePtr) & inputMask) != 0 )
  2679.                         *currByte |= outputMask;
  2680.         
  2681.                     // move onto next position in the output data                
  2682.                     outputMask <<= 1;
  2683.                     
  2684.                     // move onto the next scan line in the input data
  2685.                     thePtr += yPointerOffset;
  2686.                     
  2687.                     // Indicate we processed one of the bits
  2688.                     bitsPerByte--;
  2689.                     
  2690.                     // Keep track of our Y position as we move down the column
  2691.                     currYPos += incrY;
  2692.                 }
  2693.                 
  2694.                 if (currYPos >= endY)    //    T => We're done with this column
  2695.                     break;
  2696.                     
  2697.                 // Indicate we processed one of the byte rows in the band
  2698.                 byteSubBand--;
  2699.                 
  2700.                 // Bump to the next byte to fill in tempColumn
  2701.                 currByte++;
  2702.             }
  2703.             while (byteSubBand > 0);
  2704.         }
  2705.             
  2706.         // Save the column info (a max. of three bytes). Note: we'll only advance whichCol based upon the number of bytes per band
  2707.         BlockMove((Ptr) &tempColumn, (Ptr) &(pTheScanLine->iTheData[whichCol]), 3);
  2708.         
  2709.         // If we have some form of data, then mark that this band is dirty
  2710.         if (tempColumn != 0)
  2711.         {
  2712.             if (!bandIsDirty)    //    T => Not already dirty; remember the first dirty pixel
  2713.             {
  2714.                 /* These are the first dirty pixels we have seen so far */
  2715.                 bandIsDirty = true;
  2716.                 firstDirty = x;
  2717.             }
  2718.         }
  2719.             
  2720.         // If we have some dirty bits, adjust the whichCol variable based upon the number of bytes in a band
  2721.         if (bandIsDirty)
  2722.         {
  2723.             // Move on to the next column or set of columns
  2724.             whichCol += bytesPerBand;
  2725.         }
  2726.  
  2727.         // Position for the next bit in the input byte currently referenced by basePtr
  2728.         inputMask >>= 1;
  2729.         
  2730.         if (inputMask == 0)    //    T => Need to reset the input mask and advance the pointer
  2731.         {
  2732.             // Get the next byte
  2733.             basePtr++;
  2734.             
  2735.             // Reset the bit mask to the first bit
  2736.             inputMask = 0x80;
  2737.         }
  2738.     } // end of loop for width of gxBitmap
  2739.  
  2740.     // If we have a dirty band, fill in the left margin setting and add a carriage return to the end
  2741.     if (bandIsDirty)
  2742.     {            
  2743.         // Set the left margin to be the first dirty pixel in the scan line
  2744.         {
  2745.             SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  2746.             
  2747.             check(hGlobals);
  2748.             
  2749.             // Stuff in the set margin command
  2750.             
  2751.             pTheScanLine->cMarginsEscape = kEscape;
  2752.             pTheScanLine->cMarginsCommand = (bytesPerBand == 1) ? kLowResMarginsCommand : kHighResMarginsCommand;
  2753.             
  2754.             // Convert left margin into ASCII and place it at the start of the scan line
  2755.             Long2Dec((*hGlobals)->leftMargin + firstDirty, (Ptr) (pTheScanLine->cIndentDistance));
  2756.         }
  2757.         
  2758.         // Now fill in the last escape sequence command depending upon if we're doing low-res or high-res graphics
  2759.         
  2760.         pTheScanLine->cEscape = kEscape;
  2761.         pTheScanLine->cCommand = (bytesPerBand == 1)    ? kLowResGraphicsCommand : kHighResGraphicsCommand;
  2762.  
  2763.         // If we're doing high-res, then whichCol must be divided by three to compensate for the 3-byte buffer entries
  2764.         {
  2765.             short        adjustedWhichCol = whichCol;
  2766.             
  2767.             if (bytesPerBand == 3)
  2768.                 adjustedWhichCol /= 3;
  2769.                 
  2770.             Long2Dec(adjustedWhichCol, (Ptr) (pTheScanLine->cLineLength));
  2771.         }
  2772.         
  2773.         
  2774.         //    Increment the count of the number of bytes that have been added to the buffer
  2775.         *bufferPos += kScanLineHdrSize + whichCol;
  2776.  
  2777.         // Lastly, put a <cr> at the end of the line
  2778.         *(buffer + *bufferPos) = '\n';
  2779.         *bufferPos += 1;
  2780.     }
  2781.         
  2782.     return(anErr);
  2783. }
  2784. /* SD_RasterPackageBitmap */
  2785.  
  2786.  
  2787. /****************************************************************************************
  2788.  
  2789.                             SD_RasterLineFeed
  2790.                             
  2791.     function:
  2792.                 This routine is called by the Printing Manager to send the appropriate line
  2793.                 feed commands to the printer i norder to skip up or down the page the 
  2794.                 equivalent of lineFeedSize pixels.
  2795.                 
  2796.     parameters:    
  2797.                 lineFeedSize    number of pixels to line feed by
  2798.                 buffer            buffer in which to place the linefeed packaging commands
  2799.                 bufferPos        offset within buffer at which to place the linefeed commands
  2800.                 imageData        handle to the raster image data
  2801.                 
  2802.     returns:
  2803.                 OSErr
  2804.  
  2805. ****************************************************************************************/
  2806. OSErr SD_RasterLineFeed(short                     *lineFeedSize, 
  2807.                         Ptr                         buffer, 
  2808.                         unsigned long            *bufferPos, 
  2809.                         gxRasterImageDataHdl    imageData)
  2810. {
  2811.     OSErr        anErr = noErr;
  2812.     
  2813.     // If there is no need for any line feeds, then just return now
  2814.     if (*lineFeedSize == 0)
  2815.         return(anErr);
  2816.         
  2817.     // If we are in low res mode, we double the line feed size, as all ImageWriter LQ 
  2818.     // line feed commands are expressed at 144 dpi.
  2819.     if ( (*imageData)->vImageRes == ff(72) )
  2820.     {
  2821.         *lineFeedSize <<= 1;
  2822.         
  2823.         // do the line feed in the default way
  2824.         anErr = Forward_GXRasterLineFeed(lineFeedSize, buffer, bufferPos, imageData);
  2825.  
  2826.         *lineFeedSize >>= 1;
  2827.     }
  2828.     else    //    T => In high res. mode; must determine the number of 1/144 inch and 1/216 inch line feeds needed
  2829.     {
  2830.         Ptr        nextByte;    
  2831.         fixed        lineFeedInInches;
  2832.         fixed        oneOver144;
  2833.         fixed        remainder;
  2834.         short        num216FractLineFeeds;
  2835.         fixed        num144FractLineFeeds;
  2836.         Str31        aNumber;
  2837.                         
  2838.         // Determine the location at which we'll begin inserting commands
  2839.         nextByte = buffer + *bufferPos;
  2840.         
  2841.         // Is line feed movement going to be backward?
  2842.         if ( *lineFeedSize < 0 )
  2843.         {
  2844.             *lineFeedSize = -(*lineFeedSize);    // Force positive
  2845.             
  2846.             // Add the backward direction command to the buffer
  2847.             *nextByte++ = kEscape;
  2848.             *nextByte++ = 'r';
  2849.         }
  2850.         else    //    T => Paper motion is forward
  2851.         {
  2852.             // Add the forward direction command to the buffer
  2853.             *nextByte++ = kEscape;
  2854.             *nextByte++ = 'f';
  2855.         }
  2856.         
  2857.         // Update the count of the number of bytes added to the buffer
  2858.         *bufferPos += 2;
  2859.         
  2860.         // Determine the number of inches we need to skip with the line feed command
  2861.         lineFeedInInches = FixDiv( IntToFixed(*lineFeedSize), ff(216) );
  2862.         
  2863.         // Determine the integral number of 1/144 inch increments the line feed space comprises
  2864.         
  2865.         oneOver144 = FixDiv(ff(1), ff(144));
  2866.         num144FractLineFeeds = FixDiv( lineFeedInInches, oneOver144 );
  2867.         
  2868.         // Determine the remaining 1/216 inch line feeds we'll need to add to the buffer
  2869.         
  2870.         remainder = lineFeedInInches - FixMul( IntToFixed( FixedToInt(num144FractLineFeeds) ), oneOver144 );
  2871.         num216FractLineFeeds = FixedToInt( FixDiv( remainder, FixDiv( ff(1), ff(216) ) ) );
  2872.         
  2873.         // Send the line feed spacing commands and the line feeds necessary for the 1/144th's portion of the movement
  2874.         {
  2875.             short        numOne144ths = FixedToInt(num144FractLineFeeds);
  2876.             
  2877.             if (numOne144ths >= 99)    //    T => We can do a max. of 99/144 inch movement at a time
  2878.             {
  2879.                 //    Add the line feed spacing command to the buffer
  2880.                 *nextByte++ = kEscape;
  2881.                 *nextByte++ = 'T';
  2882.                 *nextByte++ = '9';
  2883.                 *nextByte++ = '9';
  2884.                 
  2885.                 // Update the count of the number of bytes added to the buffer
  2886.                 *bufferPos += 4;
  2887.         
  2888.                 do
  2889.                 {
  2890.                     *nextByte++ = kLineFeed;        // line feed
  2891.                     
  2892.                     // Update the count of the number of bytes added to the buffer
  2893.                     *bufferPos += 1;
  2894.         
  2895.                     numOne144ths -= 99;
  2896.                 }
  2897.                 while (numOne144ths >= 99);
  2898.             }
  2899.                 
  2900.             // Send remaining line feeds to finish off the 1/144th's portion of the movement
  2901.  
  2902.             if (numOne144ths > 0)    //    T => Still more movement
  2903.             {
  2904.                 *nextByte++ = kEscape;
  2905.                 *nextByte++ = 'T';
  2906.                 
  2907.                 NumToString(numOne144ths, aNumber);
  2908.                 if ( Length(aNumber) == 1 )
  2909.                 {
  2910.                     *nextByte++ = '0';
  2911.                     *nextByte++ = aNumber[1];
  2912.                 }
  2913.                 else
  2914.                 {
  2915.                     *nextByte++ = aNumber[1];
  2916.                     *nextByte++ = aNumber[2];
  2917.                 }
  2918.                 
  2919.                 // Add the linefeed character
  2920.                 *nextByte++ = kLineFeed;
  2921.  
  2922.                 // Update the count of the number of bytes added to the buffer
  2923.                 *bufferPos += 5;
  2924.             }
  2925.         }
  2926.         
  2927.         // Now send any spacing command for the remaining 1/216th portion of the movement if needed
  2928.         if (num216FractLineFeeds > 0)
  2929.         {
  2930.             NumToString(num216FractLineFeeds, aNumber);
  2931.             
  2932.             // Add the command to the buffer: <Esc> t <num line feeds>
  2933.             
  2934.             *nextByte++ = kEscape;
  2935.             *nextByte++ = 't';
  2936.             *nextByte = aNumber[1];
  2937.             
  2938.             // Bump the buffer byte count to account for these new characters
  2939.             *bufferPos += 3;
  2940.         }
  2941.  
  2942.         // We always handle the entire linefeed request so we can zero lineFeedSize
  2943.         *lineFeedSize = 0;
  2944.     }
  2945.  
  2946.     return(anErr);
  2947. }
  2948. /* SD_RasterLineFeed */
  2949.  
  2950.  
  2951.